BulletSim: move a bunch of common logic out of BSPrim and BSCharacter

and into the parent class BSPhysObject.
Rework collision logic to enable extra collision after done colliding.
Rename 'Scene' to 'PhysicsScene' to differentiate it from the simulator 'Scene'.
connector_plugin
Robert Adams 2012-09-18 08:39:52 -07:00
parent d26fbf727a
commit ee7cda261c
7 changed files with 361 additions and 416 deletions

View File

@ -28,7 +28,7 @@ using System;
using System.Collections.Generic;
using System.Reflection;
using log4net;
using OpenMetaverse;
using OMV = OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Physics.Manager;
@ -39,25 +39,24 @@ public class BSCharacter : BSPhysObject
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[BULLETS CHAR]";
public BSScene Scene { get; private set; }
private String _avName;
// private bool _stopped;
private Vector3 _size;
private Vector3 _scale;
private OMV.Vector3 _size;
private OMV.Vector3 _scale;
private PrimitiveBaseShape _pbs;
private uint _localID = 0;
private bool _grabbed;
private bool _selected;
private Vector3 _position;
private OMV.Vector3 _position;
private float _mass;
public float _density;
public float _avatarVolume;
private Vector3 _force;
private Vector3 _velocity;
private Vector3 _torque;
private OMV.Vector3 _force;
private OMV.Vector3 _velocity;
private OMV.Vector3 _torque;
private float _collisionScore;
private Vector3 _acceleration;
private Quaternion _orientation;
private OMV.Vector3 _acceleration;
private OMV.Quaternion _orientation;
private int _physicsActorType;
private bool _isPhysical;
private bool _flying;
@ -69,18 +68,14 @@ public class BSCharacter : BSPhysObject
private long _collidingGroundStep;
private bool _collidingObj;
private bool _floatOnWater;
private Vector3 _rotationalVelocity;
private OMV.Vector3 _rotationalVelocity;
private bool _kinematic;
private float _buoyancy;
public override BulletBody BSBody { get; set; }
public override BulletShape BSShape { get; set; }
public override BSLinkset Linkset { get; set; }
private int _subscribedEventsMs = 0;
private int _nextCollisionOkTime = 0;
private Vector3 _PIDTarget;
private OMV.Vector3 _PIDTarget;
private bool _usePID;
private float _PIDTau;
private bool _useHoverPID;
@ -88,26 +83,24 @@ public class BSCharacter : BSPhysObject
private PIDHoverType _PIDHoverType;
private float _PIDHoverTao;
public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 pos, Vector3 size, bool isFlying)
public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
{
base.BaseInitialize(parent_scene);
_localID = localID;
_avName = avName;
Scene = parent_scene;
_physicsActorType = (int)ActorTypes.Agent;
_position = pos;
_size = size;
_flying = isFlying;
_orientation = Quaternion.Identity;
_velocity = Vector3.Zero;
_orientation = OMV.Quaternion.Identity;
_velocity = OMV.Vector3.Zero;
_buoyancy = ComputeBuoyancyFromFlying(isFlying);
// The dimensions of the avatar capsule are kept in the scale.
// Physics creates a unit capsule which is scaled by the physics engine.
_scale = new Vector3(Scene.Params.avatarCapsuleRadius, Scene.Params.avatarCapsuleRadius, size.Z);
_density = Scene.Params.avatarDensity;
_scale = new OMV.Vector3(PhysicsScene.Params.avatarCapsuleRadius, PhysicsScene.Params.avatarCapsuleRadius, size.Z);
_density = PhysicsScene.Params.avatarDensity;
ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale
Linkset = new BSLinkset(Scene, this);
ShapeData shapeData = new ShapeData();
shapeData.ID = _localID;
shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
@ -118,19 +111,19 @@ public class BSCharacter : BSPhysObject
shapeData.Mass = _mass;
shapeData.Buoyancy = _buoyancy;
shapeData.Static = ShapeData.numericFalse;
shapeData.Friction = Scene.Params.avatarFriction;
shapeData.Restitution = Scene.Params.avatarRestitution;
shapeData.Friction = PhysicsScene.Params.avatarFriction;
shapeData.Restitution = PhysicsScene.Params.avatarRestitution;
// do actual create at taint time
Scene.TaintedObject("BSCharacter.create", delegate()
PhysicsScene.TaintedObject("BSCharacter.create", delegate()
{
DetailLog("{0},BSCharacter.create", _localID);
BulletSimAPI.CreateObject(Scene.WorldID, shapeData);
BulletSimAPI.CreateObject(PhysicsScene.WorldID, shapeData);
// Set the buoyancy for flying. This will be refactored when all the settings happen in C#
BulletSimAPI.SetObjectBuoyancy(Scene.WorldID, LocalID, _buoyancy);
BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(Scene.World.Ptr, LocalID));
BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(PhysicsScene.World.Ptr, LocalID));
});
return;
@ -140,9 +133,9 @@ public class BSCharacter : BSPhysObject
public override void Destroy()
{
DetailLog("{0},BSCharacter.Destroy", LocalID);
Scene.TaintedObject("BSCharacter.destroy", delegate()
PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
{
BulletSimAPI.DestroyObject(Scene.WorldID, _localID);
BulletSimAPI.DestroyObject(PhysicsScene.WorldID, _localID);
});
}
@ -154,11 +147,11 @@ public class BSCharacter : BSPhysObject
public override bool Stopped {
get { return false; }
}
public override Vector3 Size {
public override OMV.Vector3 Size {
get
{
// Avatar capsule size is kept in the scale parameter.
return new Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z);
return new OMV.Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z);
}
set {
@ -171,9 +164,9 @@ public class BSCharacter : BSPhysObject
ComputeAvatarVolumeAndMass();
Scene.TaintedObject("BSCharacter.setSize", delegate()
PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
{
BulletSimAPI.SetObjectScaleMass(Scene.WorldID, LocalID, _scale, _mass, true);
BulletSimAPI.SetObjectScaleMass(PhysicsScene.WorldID, LocalID, _scale, _mass, true);
});
}
@ -198,9 +191,27 @@ public class BSCharacter : BSPhysObject
public override void CrossingFailure() { return; }
public override void link(PhysicsActor obj) { return; }
public override void delink() { return; }
public override void LockAngularMotion(Vector3 axis) { return; }
public override Vector3 Position {
// Set motion values to zero.
// Do it to the properties so the values get set in the physics engine.
// Push the setting of the values to the viewer.
// Called at taint time!
public override void ZeroMotion()
{
_velocity = OMV.Vector3.Zero;
_acceleration = OMV.Vector3.Zero;
_rotationalVelocity = OMV.Vector3.Zero;
// Zero some other properties directly into the physics engine
BulletSimAPI.SetLinearVelocity2(BSBody.Ptr, OMV.Vector3.Zero);
BulletSimAPI.SetAngularVelocity2(BSBody.Ptr, OMV.Vector3.Zero);
BulletSimAPI.SetInterpolationVelocity2(BSBody.Ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
BulletSimAPI.ClearForces2(BSBody.Ptr);
}
public override void LockAngularMotion(OMV.Vector3 axis) { return; }
public override OMV.Vector3 Position {
get {
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
return _position;
@ -209,10 +220,10 @@ public class BSCharacter : BSPhysObject
_position = value;
PositionSanityCheck();
Scene.TaintedObject("BSCharacter.setPosition", delegate()
PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
{
DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, _localID, _position, _orientation);
});
}
}
@ -225,7 +236,7 @@ public class BSCharacter : BSPhysObject
bool ret = false;
// If below the ground, move the avatar up
float terrainHeight = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position);
float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
if (Position.Z < terrainHeight)
{
DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
@ -247,10 +258,10 @@ public class BSCharacter : BSPhysObject
{
// The new position value must be pushed into the physics engine but we can't
// just assign to "Position" because of potential call loops.
Scene.TaintedObject("BSCharacter.PositionSanityCheck", delegate()
PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", delegate()
{
DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, _localID, _position, _orientation);
});
ret = true;
}
@ -266,15 +277,15 @@ public class BSCharacter : BSPhysObject
// used when we only want this prim's mass and not the linkset thing
public override float MassRaw { get {return _mass; } }
public override Vector3 Force {
public override OMV.Vector3 Force {
get { return _force; }
set {
_force = value;
// m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
Scene.TaintedObject("BSCharacter.SetForce", delegate()
PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
{
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
BulletSimAPI.SetObjectForce(Scene.WorldID, LocalID, _force);
BulletSimAPI.SetObjectForce(PhysicsScene.WorldID, LocalID, _force);
});
}
}
@ -284,28 +295,28 @@ public class BSCharacter : BSPhysObject
set { return; }
}
public override void VehicleFloatParam(int param, float value) { }
public override void VehicleVectorParam(int param, Vector3 value) {}
public override void VehicleRotationParam(int param, Quaternion rotation) { }
public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
public override void VehicleFlags(int param, bool remove) { }
// Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
public override void SetVolumeDetect(int param) { return; }
public override Vector3 GeometricCenter { get { return Vector3.Zero; } }
public override Vector3 CenterOfMass { get { return Vector3.Zero; } }
public override Vector3 Velocity {
public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
public override OMV.Vector3 Velocity {
get { return _velocity; }
set {
_velocity = value;
// m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
Scene.TaintedObject("BSCharacter.setVelocity", delegate()
PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
{
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
BulletSimAPI.SetObjectVelocity(Scene.WorldID, _localID, _velocity);
BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, _localID, _velocity);
});
}
}
public override Vector3 Torque {
public override OMV.Vector3 Torque {
get { return _torque; }
set { _torque = value;
}
@ -315,19 +326,19 @@ public class BSCharacter : BSPhysObject
set { _collisionScore = value;
}
}
public override Vector3 Acceleration {
public override OMV.Vector3 Acceleration {
get { return _acceleration; }
set { _acceleration = value; }
}
public override Quaternion Orientation {
public override OMV.Quaternion Orientation {
get { return _orientation; }
set {
_orientation = value;
// m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
Scene.TaintedObject("BSCharacter.setOrientation", delegate()
PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
{
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, _localID, _position, _orientation);
});
}
}
@ -364,11 +375,11 @@ public class BSCharacter : BSPhysObject
set { _throttleUpdates = value; }
}
public override bool IsColliding {
get { return (_collidingStep == Scene.SimulationStep); }
get { return (_collidingStep == PhysicsScene.SimulationStep); }
set { _isColliding = value; }
}
public override bool CollidingGround {
get { return (_collidingGroundStep == Scene.SimulationStep); }
get { return (_collidingGroundStep == PhysicsScene.SimulationStep); }
set { _collidingGround = value; }
}
public override bool CollidingObj {
@ -378,7 +389,7 @@ public class BSCharacter : BSPhysObject
public override bool FloatOnWater {
set { _floatOnWater = value; }
}
public override Vector3 RotationalVelocity {
public override OMV.Vector3 RotationalVelocity {
get { return _rotationalVelocity; }
set { _rotationalVelocity = value; }
}
@ -390,16 +401,16 @@ public class BSCharacter : BSPhysObject
public override float Buoyancy {
get { return _buoyancy; }
set { _buoyancy = value;
Scene.TaintedObject("BSCharacter.setBuoyancy", delegate()
PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
{
DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
BulletSimAPI.SetObjectBuoyancy(Scene.WorldID, LocalID, _buoyancy);
BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
});
}
}
// Used for MoveTo
public override Vector3 PIDTarget {
public override OMV.Vector3 PIDTarget {
set { _PIDTarget = value; }
}
public override bool PIDActive {
@ -425,19 +436,19 @@ public class BSCharacter : BSPhysObject
}
// For RotLookAt
public override Quaternion APIDTarget { set { return; } }
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(Vector3 force, bool pushforce) {
public override void AddForce(OMV.Vector3 force, bool pushforce) {
if (force.IsFinite())
{
_force.X += force.X;
_force.Y += force.Y;
_force.Z += force.Z;
// m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
Scene.TaintedObject("BSCharacter.AddForce", delegate()
PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
{
DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
BulletSimAPI.SetObjectForce2(BSBody.Ptr, _force);
@ -450,42 +461,9 @@ public class BSCharacter : BSPhysObject
//m_lastUpdateSent = false;
}
public override void AddAngularForce(Vector3 force, bool pushforce) {
public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
}
public override void SetMomentum(Vector3 momentum) {
}
// Turn on collision events at a rate no faster than one every the given milliseconds
public override void SubscribeEvents(int ms) {
_subscribedEventsMs = ms;
if (ms > 0)
{
// make sure first collision happens
_nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
Scene.TaintedObject("BSCharacter.SubscribeEvents", delegate()
{
BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
});
}
}
public override void ZeroMotion()
{
return;
}
// Stop collision events
public override void UnSubscribeEvents() {
_subscribedEventsMs = 0;
Scene.TaintedObject("BSCharacter.UnSubscribeEvents", delegate()
{
BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
});
}
// Return 'true' if someone has subscribed to events
public override bool SubscribedEvents() {
return (_subscribedEventsMs > 0);
public override void SetMomentum(OMV.Vector3 momentum) {
}
// set _avatarVolume and _mass based on capsule size, _density and _scale
@ -520,67 +498,15 @@ public class BSCharacter : BSPhysObject
// Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
PositionSanityCheck2();
float heightHere = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position); // only for debug
float heightHere = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); // only for debug
DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5},terrain={6}",
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity, heightHere);
}
// Called by the scene when a collision with this object is reported
// The collision, if it should be reported to the character, is placed in a collection
// that will later be sent to the simulator when SendCollisions() is called.
CollisionEventUpdate collisionCollection = null;
public override bool Collide(uint collidingWith, BSPhysObject collidee, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
{
bool ret = false;
// The following makes IsColliding() and IsCollidingGround() work
_collidingStep = Scene.SimulationStep;
if (collidingWith <= Scene.TerrainManager.HighestTerrainID)
{
_collidingGroundStep = Scene.SimulationStep;
}
// DetailLog("{0},BSCharacter.Collison,call,with={1}", LocalID, collidingWith);
// throttle collisions to the rate specified in the subscription
if (SubscribedEvents()) {
int nowTime = Scene.SimulationNowTime;
if (nowTime >= _nextCollisionOkTime) {
_nextCollisionOkTime = nowTime + _subscribedEventsMs;
if (collisionCollection == null)
collisionCollection = new CollisionEventUpdate();
collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
ret = true;
}
}
return ret;
}
public override void SendCollisions()
{
/*
if (collisionCollection != null && collisionCollection.Count > 0)
{
base.SendCollisionUpdate(collisionCollection);
collisionCollection = null;
}
*/
// Kludge to make a collision call even if there are no collisions.
// This causes the avatar animation to get updated.
if (collisionCollection == null)
collisionCollection = new CollisionEventUpdate();
base.SendCollisionUpdate(collisionCollection);
// If there were any collisions in the collection, make sure we don't use the
// same instance next time.
if (collisionCollection.Count > 0)
collisionCollection = null;
// End kludge
}
// Invoke the detailed logger and output something if it's enabled.
private void DetailLog(string msg, params Object[] args)
{
Scene.PhysicsLogging.Write(msg, args);
PhysicsScene.PhysicsLogging.Write(msg, args);
}
}
}

View File

@ -539,7 +539,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// add Gravity and Buoyancy
// There is some gravity, make a gravity force vector that is applied after object velocity.
// m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
Vector3 grav = m_prim.Scene.DefaultGravity * (m_prim.Mass * (1f - m_VehicleBuoyancy));
Vector3 grav = m_prim.PhysicsScene.DefaultGravity * (m_prim.Mass * (1f - m_VehicleBuoyancy));
/*
* RA: Not sure why one would do this
@ -552,7 +552,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
// If below the terrain, move us above the ground a little.
float terrainHeight = m_prim.Scene.TerrainManager.GetTerrainHeightAtXYZ(pos);
float terrainHeight = m_prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
// Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
// Need to add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
// Vector3 rotatedSize = m_prim.Size * m_prim.Orientation;
@ -570,7 +570,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// We should hover, get the target height
if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
{
m_VhoverTargetHeight = m_prim.Scene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
m_VhoverTargetHeight = m_prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
}
if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
{
@ -849,8 +849,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Invoke the detailed logger and output something if it's enabled.
private void VDetailLog(string msg, params Object[] args)
{
if (m_prim.Scene.VehicleLoggingEnabled)
m_prim.Scene.PhysicsLogging.Write(msg, args);
if (m_prim.PhysicsScene.VehicleLoggingEnabled)
m_prim.PhysicsScene.PhysicsLogging.Write(msg, args);
}
}
}

View File

@ -36,11 +36,9 @@ public class BSLinkset
{
private static string LogHeader = "[BULLETSIM LINKSET]";
private BSPhysObject m_linksetRoot;
public BSPhysObject LinksetRoot { get { return m_linksetRoot; } }
public BSPhysObject LinksetRoot { get; protected set; }
private BSScene m_physicsScene;
public BSScene PhysicsScene { get { return m_physicsScene; } }
public BSScene PhysicsScene { get; private set; }
static int m_nextLinksetID = 1;
public int LinksetID { get; private set; }
@ -81,8 +79,8 @@ public class BSLinkset
// We create LOTS of linksets.
if (m_nextLinksetID < 0)
m_nextLinksetID = 1;
m_physicsScene = scene;
m_linksetRoot = parent;
PhysicsScene = scene;
LinksetRoot = parent;
m_children = new List<BSPhysObject>();
m_mass = parent.MassRaw;
}
@ -131,7 +129,7 @@ public class BSLinkset
// Return 'true' if the passed object is the root object of this linkset
public bool IsRoot(BSPhysObject requestor)
{
return (requestor.LocalID == m_linksetRoot.LocalID);
return (requestor.LocalID == LinksetRoot.LocalID);
}
public int NumberOfChildren { get { return m_children.Count; } }
@ -159,7 +157,7 @@ public class BSLinkset
private float ComputeLinksetMass()
{
float mass = m_linksetRoot.MassRaw;
float mass = LinksetRoot.MassRaw;
foreach (BSPhysObject bp in m_children)
{
mass += bp.MassRaw;
@ -169,8 +167,8 @@ public class BSLinkset
private OMV.Vector3 ComputeLinksetCenterOfMass()
{
OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw;
float totalMass = m_linksetRoot.MassRaw;
OMV.Vector3 com = LinksetRoot.Position * LinksetRoot.MassRaw;
float totalMass = LinksetRoot.MassRaw;
lock (m_linksetActivityLock)
{
@ -188,7 +186,7 @@ public class BSLinkset
private OMV.Vector3 ComputeLinksetGeometricCenter()
{
OMV.Vector3 com = m_linksetRoot.Position;
OMV.Vector3 com = LinksetRoot.Position;
lock (m_linksetActivityLock)
{
@ -256,7 +254,7 @@ public class BSLinkset
foreach (BSPhysObject child in m_children)
{
BSConstraint constrain;
if (m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
{
// DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
// LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
@ -306,9 +304,9 @@ public class BSLinkset
BSPhysObject rootx = LinksetRoot; // capture the root as of now
BSPhysObject childx = child;
m_physicsScene.TaintedObject("AddChildToLinkset", delegate()
PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
{
DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID);
DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID);
PhysicallyLinkAChildToRoot(rootx, childx); // build the physical binding between me and the child
});
}
@ -322,7 +320,7 @@ public class BSLinkset
// has to be updated also (like pointer to prim's parent).
private void RemoveChildFromOtherLinkset(BSPhysObject pchild)
{
pchild.Linkset = new BSLinkset(m_physicsScene, pchild);
pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
RemoveChildFromLinkset(pchild);
}
@ -334,9 +332,9 @@ public class BSLinkset
{
BSPhysObject rootx = LinksetRoot; // capture the root as of now
BSPhysObject childx = child;
m_physicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
{
DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID);
DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID);
PhysicallyUnlinkAChildFromRoot(rootx, childx);
RecomputeLinksetConstraintVariables();
@ -370,7 +368,7 @@ public class BSLinkset
DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2},rLoc={3},cLoc={4},midLoc={5}",
rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID, rootPrim.Position, childPrim.Position, midPoint);
BS6DofConstraint constrain = new BS6DofConstraint(
m_physicsScene.World, rootPrim.BSBody, childPrim.BSBody,
PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody,
midPoint,
true,
true
@ -408,7 +406,7 @@ public class BSLinkset
// ==================================================================================
*/
m_physicsScene.Constraints.AddConstraint(constrain);
PhysicsScene.Constraints.AddConstraint(constrain);
// zero linear and angular limits makes the objects unable to move in relation to each other
constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
@ -435,7 +433,7 @@ public class BSLinkset
DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
// Find the constraint for this link and get rid of it from the overall collection and from my list
m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody);
PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody);
// Make the child refresh its location
BulletSimAPI.PushUpdate2(childPrim.BSBody.Ptr);
@ -447,13 +445,13 @@ public class BSLinkset
{
DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody);
PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody);
}
// Invoke the detailed logger and output something if it's enabled.
private void DetailLog(string msg, params Object[] args)
{
m_physicsScene.PhysicsLogging.Write(msg, args);
PhysicsScene.PhysicsLogging.Write(msg, args);
}
}

View File

@ -39,26 +39,150 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// unless the difference is significant.
public abstract class BSPhysObject : PhysicsActor
{
public abstract BSLinkset Linkset { get; set; }
protected void BaseInitialize(BSScene parentScene)
{
PhysicsScene = parentScene;
Linkset = new BSLinkset(PhysicsScene, this);
public abstract bool Collide(uint collidingWith, BSPhysObject collidee,
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth);
public abstract void SendCollisions();
CollisionCollection = new CollisionEventUpdate();
SubscribedEventsMs = 0;
CollidingStep = 0;
CollidingGroundStep = 0;
}
// Return the object mass without calculating it or side effects
public BSScene PhysicsScene { get; protected set; }
public BSLinkset Linkset { get; set; }
// Return the object mass without calculating it or having side effects
public abstract float MassRaw { get; }
// Reference to the physical body (btCollisionObject) of this object
public abstract BulletBody BSBody { get; set; }
public BulletBody BSBody { get; protected set; }
// Reference to the physical shape (btCollisionShape) of this object
public abstract BulletShape BSShape { get; set; }
public BulletShape BSShape { get; protected set; }
// Stop all physical motion.
public abstract void ZeroMotion();
// Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
public virtual void StepVehicle(float timeStep) { }
// Update the physical location and motion of the object. Called with data from Bullet.
public abstract void UpdateProperties(EntityProperties entprop);
// Tell the object to clean up.
public abstract void Destroy();
#region Collisions
// Requested number of milliseconds between collision events. Zero means disabled.
protected int SubscribedEventsMs { get; set; }
// Given subscription, the time that a collision may be passed up
protected int NextCollisionOkTime { get; set; }
// The simulation step that last had a collision
protected long CollidingStep { get; set; }
// The simulation step that last had a collision with the ground
protected long CollidingGroundStep { get; set; }
// The collision flags we think are set in Bullet
protected CollisionFlags CurrentCollisionFlags { get; set; }
// The collisions that have been collected this tick
protected CollisionEventUpdate CollisionCollection;
// The simulation step is telling this object about a collision.
// Return 'true' if a collision was processed and should be sent up.
// Called at taint time from within the Step() function
public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
{
bool ret = false;
// The following lines make IsColliding() and IsCollidingGround() work
CollidingStep = PhysicsScene.SimulationStep;
if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
{
CollidingGroundStep = PhysicsScene.SimulationStep;
}
// prims in the same linkset cannot collide with each other
if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
{
return ret;
}
PhysicsScene.PhysicsLogging.Write("{0},BSPhysObject.Collison,call,with={1}", LocalID, collidingWith);
// if someone has subscribed for collision events....
if (SubscribedEvents()) {
CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
PhysicsScene.PhysicsLogging.Write("{0},BSPhysObject.Collison.AddCollider,call,with={1},point={2},normal={3},depth={4},next={5}",
LocalID, collidingWith, contactPoint, contactNormal, pentrationDepth, NextCollisionOkTime.ToString("yyyyMMddHHmmssfff"));
ret = true;
}
return ret;
}
// Routine to send the collected collisions into the simulator.
// Also handles removal of this from the collection of objects with collisions if
// there are no collisions from this object. Mechanism is create one last
// collision event to make collision_end work.
public virtual void SendCollisions()
{
// throttle the collisions to the number of milliseconds specified in the subscription
int nowTime = PhysicsScene.SimulationNowTime;
if (nowTime >= NextCollisionOkTime)
{
NextCollisionOkTime = nowTime + SubscribedEventsMs;
// We are called if we previously had collisions. If there are no collisions
// this time, send up one last empty event so OpenSim can sense collision end.
if (CollisionCollection.Count == 0)
PhysicsScene.ObjectsWithNoMoreCollisions.Add(this);
base.SendCollisionUpdate(CollisionCollection);
// The collisionCollection structure is passed around in the simulator.
// Make sure we don't have a handle to that one and that a new one is used next time.
CollisionCollection = new CollisionEventUpdate();
}
}
// Subscribe for collision events.
// Parameter is the millisecond rate the caller wishes collision events to occur.
public override void SubscribeEvents(int ms) {
SubscribedEventsMs = ms;
if (ms > 0)
{
// make sure first collision happens
NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
PhysicsScene.PhysicsLogging.Write("{0},SubscribeEvents,call,ms={1},nextOKTime={2}",
LocalID, SubscribedEventsMs, NextCollisionOkTime.ToString("yyyyMMddHHmmssfff"));
PhysicsScene.TaintedObject("BSPhysObject.SubscribeEvents", delegate()
{
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
});
}
else
{
// Subscribing for zero or less is the same as unsubscribing
UnSubscribeEvents();
}
}
public override void UnSubscribeEvents() {
SubscribedEventsMs = 0;
PhysicsScene.PhysicsLogging.Write("{0},UnSubscribeEvents,call", LocalID);
PhysicsScene.TaintedObject("BSPhysObject.UnSubscribeEvents", delegate()
{
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
});
}
// Return 'true' if the simulator wants collision events
public override bool SubscribedEvents() {
return (SubscribedEventsMs > 0);
}
#endregion // Collisions
}
}

View File

@ -49,8 +49,6 @@ public sealed class BSPrim : BSPhysObject
private ulong _hullKey;
private List<ConvexResult> _hulls;
private BSScene _scene;
public BSScene Scene { get { return _scene; } }
private String _avName;
private uint _localID = 0;
@ -87,18 +85,6 @@ public sealed class BSPrim : BSPhysObject
private bool _kinematic;
private float _buoyancy;
// Membership in a linkset is controlled by this class.
public override BSLinkset Linkset { get; set; }
private int _subscribedEventsMs = 0;
private int _nextCollisionOkTime = 0;
long _collidingStep;
long _collidingGroundStep;
CollisionFlags m_currentCollisionFlags = 0;
public override BulletBody BSBody { get; set; }
public override BulletShape BSShape { get; set; }
private BSDynamics _vehicle;
private OMV.Vector3 _PIDTarget;
@ -113,10 +99,10 @@ public sealed class BSPrim : BSPhysObject
OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
{
// m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
base.BaseInitialize(parent_scene);
_localID = localID;
_avName = primName;
_physicsActorType = (int)ActorTypes.Prim;
_scene = parent_scene;
_position = pos;
_size = size;
_scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
@ -129,25 +115,23 @@ public sealed class BSPrim : BSPhysObject
_pbs = pbs;
_isPhysical = pisPhysical;
_isVolumeDetect = false;
_subscribedEventsMs = 0;
_friction = _scene.Params.defaultFriction; // TODO: compute based on object material
_density = _scene.Params.defaultDensity; // TODO: compute based on object material
_restitution = _scene.Params.defaultRestitution;
Linkset = new BSLinkset(Scene, this); // a linkset of one
_vehicle = new BSDynamics(Scene, this); // add vehicleness
_friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material
_density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material
_restitution = PhysicsScene.Params.defaultRestitution;
_vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
_mass = CalculateMass();
DetailLog("{0},BSPrim.constructor,call", LocalID);
// do the actual object creation at taint time
_scene.TaintedObject("BSPrim.create", delegate()
PhysicsScene.TaintedObject("BSPrim.create", delegate()
{
CreateGeomAndObject(true);
// Get the pointer to the physical body for this object.
// At the moment, we're still letting BulletSim manage the creation and destruction
// of the object. Someday we'll move that into the C# code.
BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(PhysicsScene.World.Ptr, LocalID));
BSShape = new BulletShape(BulletSimAPI.GetCollisionShape2(BSBody.Ptr));
m_currentCollisionFlags = BulletSimAPI.GetCollisionFlags2(BSBody.Ptr);
CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(BSBody.Ptr);
});
}
@ -168,11 +152,11 @@ public sealed class BSPrim : BSPhysObject
// Undo any vehicle properties
this.VehicleType = (int)Vehicle.TYPE_NONE;
_scene.TaintedObject("BSPrim.destroy", delegate()
PhysicsScene.TaintedObject("BSPrim.destroy", delegate()
{
DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
// everything in the C# world will get garbage collected. Tell the C++ world to free stuff.
BulletSimAPI.DestroyObject(_scene.WorldID, LocalID);
BulletSimAPI.DestroyObject(PhysicsScene.WorldID, LocalID);
});
}
@ -183,7 +167,7 @@ public sealed class BSPrim : BSPhysObject
get { return _size; }
set {
_size = value;
_scene.TaintedObject("BSPrim.setSize", delegate()
PhysicsScene.TaintedObject("BSPrim.setSize", delegate()
{
_mass = CalculateMass(); // changing size changes the mass
// Since _size changed, the mesh needs to be rebuilt. If rebuilt, all the correct
@ -196,7 +180,7 @@ public sealed class BSPrim : BSPhysObject
public override PrimitiveBaseShape Shape {
set {
_pbs = value;
_scene.TaintedObject("BSPrim.setShape", delegate()
PhysicsScene.TaintedObject("BSPrim.setShape", delegate()
{
_mass = CalculateMass(); // changing the shape changes the mass
CreateGeomAndObject(false);
@ -214,7 +198,7 @@ public sealed class BSPrim : BSPhysObject
public override bool Selected {
set {
_isSelected = value;
_scene.TaintedObject("BSPrim.setSelected", delegate()
PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
{
SetObjectDynamic();
});
@ -283,13 +267,13 @@ public sealed class BSPrim : BSPhysObject
_position = BulletSimAPI.GetPosition2(BSBody.Ptr);
// don't do the GetObjectPosition for root elements because this function is called a zillion times
// _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
return _position;
}
set {
_position = value;
// TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
_scene.TaintedObject("BSPrim.setPosition", delegate()
PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
{
DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetTranslation2(BSBody.Ptr, _position, _orientation);
@ -327,7 +311,7 @@ public sealed class BSPrim : BSPhysObject
get { return _force; }
set {
_force = value;
_scene.TaintedObject("BSPrim.setForce", delegate()
PhysicsScene.TaintedObject("BSPrim.setForce", delegate()
{
DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
BulletSimAPI.SetObjectForce2(BSBody.Ptr, _force);
@ -342,40 +326,40 @@ public sealed class BSPrim : BSPhysObject
set {
Vehicle type = (Vehicle)value;
BSPrim vehiclePrim = this;
_scene.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.ProcessTypeChange(type);
// Tell the scene about the vehicle so it will get processing each frame.
_scene.VehicleInSceneTypeChanged(this, type);
PhysicsScene.VehicleInSceneTypeChanged(this, type);
});
}
}
public override void VehicleFloatParam(int param, float value)
{
_scene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
{
_vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
});
}
public override void VehicleVectorParam(int param, OMV.Vector3 value)
{
_scene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
{
_vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
});
}
public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
{
_scene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
{
_vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
});
}
public override void VehicleFlags(int param, bool remove)
{
_scene.TaintedObject("BSPrim.VehicleFlags", delegate()
PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate()
{
_vehicle.ProcessVehicleFlags(param, remove);
});
@ -393,8 +377,9 @@ public sealed class BSPrim : BSPhysObject
public override void SetVolumeDetect(int param) {
bool newValue = (param != 0);
_isVolumeDetect = newValue;
_scene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
{
DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
SetObjectDynamic();
});
return;
@ -404,7 +389,7 @@ public sealed class BSPrim : BSPhysObject
get { return _velocity; }
set {
_velocity = value;
_scene.TaintedObject("BSPrim.setVelocity", delegate()
PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
{
DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
BulletSimAPI.SetLinearVelocity2(BSBody.Ptr, _velocity);
@ -438,9 +423,9 @@ public sealed class BSPrim : BSPhysObject
set {
_orientation = value;
// TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
_scene.TaintedObject("BSPrim.setOrientation", delegate()
PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
{
// _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetTranslation2(BSBody.Ptr, _position, _orientation);
});
@ -454,8 +439,9 @@ public sealed class BSPrim : BSPhysObject
get { return _isPhysical; }
set {
_isPhysical = value;
_scene.TaintedObject("BSPrim.setIsPhysical", delegate()
PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
{
DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
SetObjectDynamic();
});
}
@ -493,9 +479,9 @@ public sealed class BSPrim : BSPhysObject
// Bullet wants static objects to have a mass of zero
float mass = IsStatic ? 0f : _mass;
BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass);
BulletSimAPI.SetObjectProperties(Scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass);
*/
BulletSimAPI.RemoveObjectFromWorld2(Scene.World.Ptr, BSBody.Ptr);
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.Ptr, BSBody.Ptr);
// Set up the object physicalness (does gravity and collisions move this object)
MakeDynamic(IsStatic);
@ -506,15 +492,15 @@ public sealed class BSPrim : BSPhysObject
// Arrange for collisions events if the simulator wants them
EnableCollisions(SubscribedEvents());
BulletSimAPI.AddObjectToWorld2(Scene.World.Ptr, BSBody.Ptr);
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.Ptr, BSBody.Ptr);
// Recompute any linkset parameters.
// When going from non-physical to physical, this re-enables the constraints that
// had been automatically disabled when the mass was set to zero.
Linkset.Refresh(this);
DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,static={1},solid={2},mass={3}, cf={4}",
LocalID, IsStatic, IsSolid, _mass, m_currentCollisionFlags);
DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,static={1},solid={2},mass={3},collide={4},cf={5}",
LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags);
}
// "Making dynamic" means changing to and from static.
@ -527,7 +513,7 @@ public sealed class BSPrim : BSPhysObject
if (makeStatic)
{
// Become a Bullet 'static' object type
m_currentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_STATIC_OBJECT);
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_STATIC_OBJECT);
// Stop all movement
BulletSimAPI.ClearAllForces2(BSBody.Ptr);
// Center of mass is at the center of the object
@ -539,16 +525,17 @@ public sealed class BSPrim : BSPhysObject
// There can be special things needed for implementing linksets
Linkset.MakeStatic(this);
// The activation state is 'sleeping' so Bullet will not try to act on it
BulletSimAPI.ForceActivationState2(BSBody.Ptr, ActivationState.ISLAND_SLEEPING);
// BulletSimAPI.ForceActivationState2(BSBody.Ptr, ActivationState.ISLAND_SLEEPING);
BulletSimAPI.ForceActivationState2(BSBody.Ptr, ActivationState.DISABLE_SIMULATION);
}
else
{
// Not a Bullet static object
m_currentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_STATIC_OBJECT);
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_STATIC_OBJECT);
// Set various physical properties so internal things will get computed correctly as they are set
BulletSimAPI.SetFriction2(BSBody.Ptr, Scene.Params.defaultFriction);
BulletSimAPI.SetRestitution2(BSBody.Ptr, Scene.Params.defaultRestitution);
// Set various physical properties so internal dynamic properties will get computed correctly as they are set
BulletSimAPI.SetFriction2(BSBody.Ptr, PhysicsScene.Params.defaultFriction);
BulletSimAPI.SetRestitution2(BSBody.Ptr, PhysicsScene.Params.defaultRestitution);
// per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
BulletSimAPI.SetInterpolationLinearVelocity2(BSBody.Ptr, OMV.Vector3.Zero);
BulletSimAPI.SetInterpolationAngularVelocity2(BSBody.Ptr, OMV.Vector3.Zero);
@ -562,10 +549,10 @@ public sealed class BSPrim : BSPhysObject
BulletSimAPI.UpdateInertiaTensor2(BSBody.Ptr);
// Various values for simulation limits
BulletSimAPI.SetDamping2(BSBody.Ptr, Scene.Params.linearDamping, Scene.Params.angularDamping);
BulletSimAPI.SetDeactivationTime2(BSBody.Ptr, Scene.Params.deactivationTime);
BulletSimAPI.SetSleepingThresholds2(BSBody.Ptr, Scene.Params.linearSleepingThreshold, Scene.Params.angularSleepingThreshold);
BulletSimAPI.SetContactProcessingThreshold2(BSBody.Ptr, Scene.Params.contactProcessingThreshold);
BulletSimAPI.SetDamping2(BSBody.Ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
BulletSimAPI.SetDeactivationTime2(BSBody.Ptr, PhysicsScene.Params.deactivationTime);
BulletSimAPI.SetSleepingThresholds2(BSBody.Ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
BulletSimAPI.SetContactProcessingThreshold2(BSBody.Ptr, PhysicsScene.Params.contactProcessingThreshold);
// There can be special things needed for implementing linksets
Linkset.MakeDynamic(this);
@ -581,11 +568,11 @@ public sealed class BSPrim : BSPhysObject
if (makeSolid)
{
// Easy in Bullet -- just remove the object flag that controls collision response
m_currentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
}
else
{
m_currentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
}
}
@ -594,11 +581,11 @@ public sealed class BSPrim : BSPhysObject
{
if (wantsCollisionEvents)
{
m_currentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
}
else
{
m_currentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
}
}
@ -618,11 +605,11 @@ public sealed class BSPrim : BSPhysObject
set { _throttleUpdates = value; }
}
public override bool IsColliding {
get { return (_collidingStep == _scene.SimulationStep); }
get { return (CollidingStep == PhysicsScene.SimulationStep); }
set { _isColliding = value; }
}
public override bool CollidingGround {
get { return (_collidingGroundStep == _scene.SimulationStep); }
get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
set { _collidingGround = value; }
}
public override bool CollidingObj {
@ -656,7 +643,7 @@ public sealed class BSPrim : BSPhysObject
set {
_rotationalVelocity = value;
// m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
_scene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
{
DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
BulletSimAPI.SetAngularVelocity2(BSBody.Ptr, _rotationalVelocity);
@ -673,13 +660,13 @@ public sealed class BSPrim : BSPhysObject
get { return _buoyancy; }
set {
_buoyancy = value;
_scene.TaintedObject("BSPrim.setBuoyancy", delegate()
PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
{
DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
// Buoyancy is faked by changing the gravity applied to the object
float grav = Scene.Params.gravity * (1f - _buoyancy);
float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
BulletSimAPI.SetGravity2(BSBody.Ptr, new OMV.Vector3(0f, 0f, grav));
// BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
// BulletSimAPI.SetObjectBuoyancy(Scene.WorldID, _localID, _buoyancy);
});
}
}
@ -730,7 +717,7 @@ public sealed class BSPrim : BSPhysObject
m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
return;
}
_scene.TaintedObject("BSPrim.AddForce", delegate()
PhysicsScene.TaintedObject("BSPrim.AddForce", delegate()
{
OMV.Vector3 fSum = OMV.Vector3.Zero;
lock (m_accumulatedForces)
@ -754,30 +741,6 @@ public sealed class BSPrim : BSPhysObject
public override void SetMomentum(OMV.Vector3 momentum) {
DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
}
public override void SubscribeEvents(int ms) {
_subscribedEventsMs = ms;
if (ms > 0)
{
// make sure first collision happens
_nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
Scene.TaintedObject("BSPrim.SubscribeEvents", delegate()
{
m_currentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
});
}
}
public override void UnSubscribeEvents() {
_subscribedEventsMs = 0;
Scene.TaintedObject("BSPrim.UnSubscribeEvents", delegate()
{
m_currentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
});
}
public override bool SubscribedEvents() {
return (_subscribedEventsMs > 0);
}
#region Mass Calculation
private float CalculateMass()
@ -1071,8 +1034,8 @@ public sealed class BSPrim : BSPhysObject
if (returnMass <= 0)
returnMass = 0.0001f;
if (returnMass > _scene.MaximumObjectMass)
returnMass = _scene.MaximumObjectMass;
if (returnMass > PhysicsScene.MaximumObjectMass)
returnMass = PhysicsScene.MaximumObjectMass;
return returnMass;
}// end CalculateMass
@ -1090,7 +1053,7 @@ public sealed class BSPrim : BSPhysObject
bool haveShape = false;
// If the prim attributes are simple, this could be a simple Bullet native shape
if ((_pbs.SculptEntry && !Scene.ShouldMeshSculptedPrim)
if ((_pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
|| (_pbs.ProfileBegin == 0 && _pbs.ProfileEnd == 0
&& _pbs.ProfileHollow == 0
&& _pbs.PathTwist == 0 && _pbs.PathTwistBegin == 0
@ -1156,12 +1119,12 @@ public sealed class BSPrim : BSPhysObject
private bool CreateGeomMesh()
{
// level of detail based on size and type of the object
float lod = _scene.MeshLOD;
float lod = PhysicsScene.MeshLOD;
if (_pbs.SculptEntry)
lod = _scene.SculptLOD;
lod = PhysicsScene.SculptLOD;
float maxAxis = Math.Max(_size.X, Math.Max(_size.Y, _size.Z));
if (maxAxis > _scene.MeshMegaPrimThreshold)
lod = _scene.MeshMegaPrimLOD;
if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
lod = PhysicsScene.MeshMegaPrimLOD;
ulong newMeshKey = (ulong)_pbs.GetMeshKey(_size, lod);
// m_log.DebugFormat("{0}: CreateGeomMesh: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _meshKey, newMeshKey);
@ -1175,14 +1138,14 @@ public sealed class BSPrim : BSPhysObject
{
// m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey);
DetailLog("{0},BSPrim.CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey);
BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
BulletSimAPI.DestroyMesh(PhysicsScene.WorldID, _meshKey);
_mesh = null;
_meshKey = 0;
}
_meshKey = newMeshKey;
// always pass false for physicalness as this creates some sort of bounding box which we don't need
_mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, lod, false);
_mesh = PhysicsScene.mesher.CreateMesh(_avName, _pbs, _size, lod, false);
int[] indices = _mesh.getIndexListAsInt();
List<OMV.Vector3> vertices = _mesh.getVertexList();
@ -1198,7 +1161,7 @@ public sealed class BSPrim : BSPhysObject
// m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
// LogHeader, _localID, _meshKey, indices.Length, vertices.Count);
BulletSimAPI.CreateMesh(_scene.WorldID, _meshKey, indices.GetLength(0), indices,
BulletSimAPI.CreateMesh(PhysicsScene.WorldID, _meshKey, indices.GetLength(0), indices,
vertices.Count, verticesAsFloats);
_shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH;
@ -1211,7 +1174,7 @@ public sealed class BSPrim : BSPhysObject
// Returns 'true' of a mesh was actually rebuild (we could also have one of these specs).
private bool CreateGeomHull()
{
float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD;
float lod = _pbs.SculptEntry ? PhysicsScene.SculptLOD : PhysicsScene.MeshLOD;
ulong newHullKey = (ulong)_pbs.GetMeshKey(_size, lod);
// m_log.DebugFormat("{0}: CreateGeomHull: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _hullKey, newHullKey);
@ -1225,7 +1188,7 @@ public sealed class BSPrim : BSPhysObject
{
// m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
DetailLog("{0},BSPrim.CreateGeomHull,deleteOldHull,key={1}", LocalID, _hullKey);
BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
BulletSimAPI.DestroyHull(PhysicsScene.WorldID, _hullKey);
_hullKey = 0;
}
@ -1314,7 +1277,7 @@ public sealed class BSPrim : BSPhysObject
// create the hull definition in Bullet
// m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount);
BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls);
BulletSimAPI.CreateHull(PhysicsScene.WorldID, _hullKey, hullCount, convHulls);
_shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
// meshes are already scaled by the meshmerizer
_scale = new OMV.Vector3(1f, 1f, 1f);
@ -1354,10 +1317,10 @@ public sealed class BSPrim : BSPhysObject
ShapeData shape;
FillShapeInfo(out shape);
// m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type);
bool ret = BulletSimAPI.CreateObject(_scene.WorldID, shape);
bool ret = BulletSimAPI.CreateObject(PhysicsScene.WorldID, shape);
// the CreateObject() may have recreated the rigid body. Make sure we have the latest address.
BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(PhysicsScene.World.Ptr, LocalID));
BSShape = new BulletShape(BulletSimAPI.GetCollisionShape2(BSBody.Ptr));
return ret;
@ -1490,61 +1453,10 @@ public sealed class BSPrim : BSPhysObject
}
*/
}
// I've collided with something
// Called at taint time from within the Step() function
CollisionEventUpdate collisionCollection;
public override bool Collide(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
{
bool ret = false;
// The following lines make IsColliding() and IsCollidingGround() work
_collidingStep = Scene.SimulationStep;
if (collidingWith <= Scene.TerrainManager.HighestTerrainID)
{
_collidingGroundStep = Scene.SimulationStep;
}
// DetailLog("{0},BSPrim.Collison,call,with={1}", LocalID, collidingWith);
// prims in the same linkset cannot collide with each other
if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
{
return ret;
}
// if someone has subscribed for collision events....
if (SubscribedEvents()) {
// throttle the collisions to the number of milliseconds specified in the subscription
int nowTime = Scene.SimulationNowTime;
if (nowTime >= _nextCollisionOkTime) {
_nextCollisionOkTime = nowTime + _subscribedEventsMs;
if (collisionCollection == null)
collisionCollection = new CollisionEventUpdate();
collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
ret = true;
}
}
return ret;
}
// The scene is telling us it's time to pass our collected collisions into the simulator
public override void SendCollisions()
{
if (collisionCollection != null && collisionCollection.Count > 0)
{
base.SendCollisionUpdate(collisionCollection);
// The collisionCollection structure is passed around in the simulator.
// Make sure we don't have a handle to that one and that a new one is used next time.
collisionCollection = null;
}
}
// Invoke the detailed logger and output something if it's enabled.
private void DetailLog(string msg, params Object[] args)
{
Scene.PhysicsLogging.Write(msg, args);
PhysicsScene.PhysicsLogging.Write(msg, args);
}
}
}

View File

@ -75,10 +75,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public Dictionary<uint, BSPhysObject> PhysObjects = new Dictionary<uint, BSPhysObject>();
private HashSet<BSPhysObject> m_objectsWithCollisions = new HashSet<BSPhysObject>();
// Following is a kludge and can be removed when avatar animation updating is
// moved to a better place.
private HashSet<BSPhysObject> m_avatarsWithCollisions = new HashSet<BSPhysObject>();
public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
// Keep track of all the avatars so we can send them a collision event
// every tick so OpenSim will update its animation.
private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
// List of all the objects that have vehicle properties and should be called
// to update each physics step.
@ -379,7 +380,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// TODO: Remove kludge someday.
// We must generate a collision for avatars whether they collide or not.
// This is required by OpenSim to update avatar animations, etc.
lock (m_avatarsWithCollisions) m_avatarsWithCollisions.Add(actor);
lock (m_avatars) m_avatars.Add(actor);
return actor;
}
@ -397,7 +398,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
{
lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
// Remove kludge someday
lock (m_avatarsWithCollisions) m_avatarsWithCollisions.Remove(bsactor);
lock (m_avatars) m_avatars.Remove(bsactor);
}
catch (Exception e)
{
@ -464,6 +465,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
int collidersCount = 0;
IntPtr collidersPtr;
int beforeTime = 0;
int simTime = 0;
// prevent simulation until we've been initialized
if (!m_initialized) return 5.0f;
@ -481,10 +485,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters
int numSubSteps = 0;
try
{
if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
DetailLog("{0},Simulate,call, nTaints= {1}, substeps={2}, updates={3}, colliders={4}",
DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
DetailLog("{0},Simulate,call, nTaints={1}, simTime={2}, substeps={3}, updates={4}, colliders={5}",
DetailLogZero, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
}
catch (Exception e)
{
@ -502,12 +510,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// Get a value for 'now' so all the collision and update routines don't have to get their own
SimulationNowTime = Util.EnvironmentTickCount();
// This is a kludge to get avatar movement updates.
// ODE sends collisions for avatars even if there are have been no collisions. This updates
// avatar animations and stuff.
// If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
m_objectsWithCollisions = new HashSet<BSPhysObject>(m_avatarsWithCollisions);
// If there were collisions, process them by sending the event to the prim.
// Collisions must be processed before updates.
if (collidersCount > 0)
@ -523,11 +525,31 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
}
// This is a kludge to get avatar movement updates.
// ODE sends collisions for avatars even if there are have been no collisions. This updates
// avatar animations and stuff.
// If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
foreach (BSPhysObject bsp in m_avatars)
bsp.SendCollisions();
// The above SendCollision's batch up the collisions on the objects.
// Now push the collisions into the simulator.
foreach (BSPhysObject bsp in m_objectsWithCollisions)
bsp.SendCollisions();
m_objectsWithCollisions.Clear();
// If the object is done colliding, it will add itself to the ObjectsWithNoMoreCollisions list.
if (ObjectsWithCollisions.Count > 0)
{
foreach (BSPhysObject bsp in ObjectsWithCollisions)
if (!m_avatars.Contains(bsp)) // don't call avatars twice
bsp.SendCollisions();
}
// Objects that are done colliding are removed from the ObjectsWithCollisions list.
// This can't be done by SendCollisions because it is inside an iteration of ObjectWithCollisions.
if (ObjectsWithNoMoreCollisions.Count > 0)
{
foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
ObjectsWithCollisions.Remove(po);
ObjectsWithNoMoreCollisions.Clear();
}
// If any of the objects had updated properties, tell the object it has been changed by the physics engine
if (updatedEntityCount > 0)
@ -555,7 +577,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// The physics engine returns the number of milliseconds it simulated this call.
// These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
// Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS.
return numSubSteps * m_fixedTimeStep;
return numSubSteps * m_fixedTimeStep * 1000;
}
// Something has collided
@ -583,7 +605,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
{
// If a collision was posted, remember to send it to the simulator
m_objectsWithCollisions.Add(collider);
ObjectsWithCollisions.Add(collider);
}
return;

View File

@ -249,7 +249,16 @@ public enum CollisionFlags : uint
BS_PHYSICAL_OBJECT = 1 << 13,
BS_TERRAIN_OBJECT = 1 << 14,
BS_NONE = 0,
BS_ALL = 0xFFFFFFFF
BS_ALL = 0xFFFFFFFF,
// These are the collision flags switched depending on physical state.
// The other flags are used for other things and should not be fooled with.
BS_ACTIVE = CF_STATIC_OBJECT
| CF_KINEMATIC_OBJECT
| CF_NO_CONTACT_RESPONSE
| BS_VOLUME_DETECT_OBJECT
| BS_PHANTOM_OBJECT
| BS_PHYSICAL_OBJECT,
};
// Values for collisions groups and masks
@ -270,52 +279,6 @@ public enum CollisionFilterGroups : uint
SolidFilter = 1 << 13,
};
// For each type, we first clear and then set the collision flags
public enum ClearCollisionFlag : uint
{
Terrain = CollisionFlags.BS_ALL,
Phantom = CollisionFlags.BS_ALL,
VolumeDetect = CollisionFlags.BS_ALL,
PhysicalObject = CollisionFlags.BS_ALL,
StaticObject = CollisionFlags.BS_ALL
}
public enum SetCollisionFlag : uint
{
Terrain = CollisionFlags.CF_STATIC_OBJECT
| CollisionFlags.BS_TERRAIN_OBJECT,
Phantom = CollisionFlags.CF_STATIC_OBJECT
| CollisionFlags.BS_PHANTOM_OBJECT
| CollisionFlags.CF_NO_CONTACT_RESPONSE,
VolumeDetect = CollisionFlags.CF_STATIC_OBJECT
| CollisionFlags.BS_VOLUME_DETECT_OBJECT
| CollisionFlags.CF_NO_CONTACT_RESPONSE,
PhysicalObject = CollisionFlags.BS_PHYSICAL_OBJECT,
StaticObject = CollisionFlags.CF_STATIC_OBJECT,
}
// Collision filters used for different types of objects
public enum SetCollisionFilter : uint
{
Terrain = CollisionFilterGroups.AllFilter,
Phantom = CollisionFilterGroups.GroundPlaneFilter
| CollisionFilterGroups.TerrainFilter,
VolumeDetect = CollisionFilterGroups.AllFilter,
PhysicalObject = CollisionFilterGroups.AllFilter,
StaticObject = CollisionFilterGroups.AllFilter,
}
// Collision masks used for different types of objects
public enum SetCollisionMask : uint
{
Terrain = CollisionFilterGroups.AllFilter,
Phantom = CollisionFilterGroups.GroundPlaneFilter
| CollisionFilterGroups.TerrainFilter,
VolumeDetect = CollisionFilterGroups.AllFilter,
PhysicalObject = CollisionFilterGroups.AllFilter,
StaticObject = CollisionFilterGroups.AllFilter
}
// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
public enum ConstraintParams : int