BulletSim: refactor all the linkset logic out of the prim class

and into its own class. The BulletSim data structures track
individual prims as linksets of 1 so most of the prim code is not
different between a linked and unlinked object.
0.7.4.1
Robert Adams 2012-07-26 14:54:57 -07:00
parent d4a667a918
commit 7d30637d51
5 changed files with 411 additions and 237 deletions

View File

@ -0,0 +1,308 @@
/*
* 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;
using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSLinkset
{
private static string LogHeader = "[BULLETSIM LINKSET]";
private BSPrim m_linksetRoot;
public BSPrim Root { get { return m_linksetRoot; } }
private BSScene m_scene;
private List<BSPrim> m_children;
// We lock the diddling of linkset classes to prevent any badness.
// This locks the modification of the instances of this class. Changes
// to the physical representation is done via the tainting mechenism.
private object m_linksetActivityLock = new Object();
// We keep the prim's mass in the linkset structure since it could be dependent on other prims
private float m_mass;
public float Mass
{
get
{
m_mass = ComputeLinksetMass();
return m_mass;
}
}
public OMV.Vector3 CenterOfMass
{
get { return ComputeLinksetCenterOfMass(); }
}
public OMV.Vector3 GeometricCenter
{
get { return ComputeLinksetGeometricCenter(); }
}
public BSLinkset(BSScene scene, BSPrim parent)
{
// A simple linkset of one (no children)
m_scene = scene;
m_linksetRoot = parent;
m_children = new List<BSPrim>();
m_mass = parent.MassRaw;
}
// Link to a linkset where the child knows the parent.
// Parent changing should not happen so do some sanity checking.
// We return the parent's linkset so the child can track it's membership.
public BSLinkset AddMeToLinkset(BSPrim child, BSPrim parent)
{
lock (m_linksetActivityLock)
{
parent.Linkset.AddChildToLinkset(child);
}
return parent.Linkset;
}
public BSLinkset RemoveMeFromLinkset(BSPrim child)
{
lock (m_linksetActivityLock)
{
if (IsRoot(child))
{
// if root of linkset, take the linkset apart
while (m_children.Count > 0)
{
// Note that we don't do a foreach because the remove routine
// takes it out of the list.
RemoveChildFromLinkset(m_children[0]);
}
m_children.Clear(); // just to make sure
}
else
{
// Just removing a child from an existing linkset
RemoveChildFromLinkset(child);
}
}
// The child is down to a linkset of just itself
return new BSLinkset(m_scene, child);
}
// An existing linkset had one of its members rebuilt or something.
// Undo all the physical linking and rebuild the physical linkset.
public bool RefreshLinkset(BSPrim requestor)
{
return true;
}
// Return 'true' if the passed object is the root object of this linkset
public bool IsRoot(BSPrim requestor)
{
return (requestor.LocalID == m_linksetRoot.LocalID);
}
// Return 'true' if this linkset has any children (more than the root member)
public bool HasAnyChildren { get { return (m_children.Count > 0); } }
// Return 'true' if this child is in this linkset
public bool HasChild(BSPrim child)
{
bool ret = false;
foreach (BSPrim bp in m_children)
{
if (child.LocalID == bp.LocalID)
{
ret = true;
break;
}
}
return ret;
}
private float ComputeLinksetMass()
{
float mass = m_linksetRoot.Mass;
foreach (BSPrim bp in m_children)
{
mass += bp.Mass;
}
return mass;
}
private OMV.Vector3 ComputeLinksetCenterOfMass()
{
OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw;
float totalMass = m_linksetRoot.MassRaw;
foreach (BSPrim bp in m_children)
{
com += bp.Position * bp.MassRaw;
totalMass += bp.MassRaw;
}
com /= totalMass;
return com;
}
private OMV.Vector3 ComputeLinksetGeometricCenter()
{
OMV.Vector3 com = m_linksetRoot.Position;
foreach (BSPrim bp in m_children)
{
com += bp.Position * bp.MassRaw;
}
com /= m_children.Count + 1;
return com;
}
// I am the root of a linkset and a new child is being added
public void AddChildToLinkset(BSPrim pchild)
{
BSPrim child = pchild;
if (!HasChild(child))
{
m_children.Add(child);
m_scene.TaintedObject(delegate()
{
DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID);
DetailLog("{0},AddChildToLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID);
PhysicallyLinkAChildToRoot(pchild); // build the physical binding between me and the child
});
}
return;
}
// I am the root of a linkset and one of my children is being removed.
// Safe to call even if the child is not really in my linkset.
public void RemoveChildFromLinkset(BSPrim pchild)
{
BSPrim child = pchild;
if (m_children.Remove(child))
{
m_scene.TaintedObject(delegate()
{
DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID);
DetailLog("{0},RemoveChildFromLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID);
if (m_children.Count == 0)
{
// if the linkset is empty, make sure all linkages have been removed
PhysicallyUnlinkAllChildrenFromRoot();
}
else
{
PhysicallyUnlinkAChildFromRoot(pchild);
}
});
}
else
{
// This will happen if we remove the root of the linkset first. Non-fatal occurance.
// m_scene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
}
return;
}
// Create a constraint between me (root of linkset) and the passed prim (the child).
// Called at taint time!
private void PhysicallyLinkAChildToRoot(BSPrim childPrim)
{
// Zero motion for children so they don't interpolate
childPrim.ZeroMotion();
// relative position normalized to the root prim
OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(m_linksetRoot.Orientation);
OMV.Vector3 childRelativePosition = (childPrim.Position - m_linksetRoot.Position) * invThisOrientation;
// relative rotation of the child to the parent
OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
// create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
// DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID);
DetailLog("{0},LinkAChildToMe,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID);
BSConstraint constrain = m_scene.Constraints.CreateConstraint(
m_scene.World, m_linksetRoot.Body, childPrim.Body,
childRelativePosition,
childRelativeRotation,
OMV.Vector3.Zero,
OMV.Quaternion.Identity);
constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
// tweek the constraint to increase stability
constrain.UseFrameOffset(m_scene.BoolNumeric(m_scene.Params.linkConstraintUseFrameOffset));
constrain.TranslationalLimitMotor(m_scene.BoolNumeric(m_scene.Params.linkConstraintEnableTransMotor),
m_scene.Params.linkConstraintTransMotorMaxVel,
m_scene.Params.linkConstraintTransMotorMaxForce);
}
// Remove linkage between myself and a particular child
// Called at taint time!
private void PhysicallyUnlinkAChildFromRoot(BSPrim childPrim)
{
DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}",
LogHeader, m_linksetRoot.LocalID, childPrim.LocalID);
DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID);
// BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, childPrim.LocalID);
m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body, childPrim.Body);
}
// Remove linkage between myself and any possible children I might have
// Called at taint time!
private void PhysicallyUnlinkAllChildrenFromRoot()
{
// DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader);
DetailLog("{0},PhysicallyUnlinkAllChildren,taint", m_linksetRoot.LocalID);
m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body);
// BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID);
}
// Invoke the detailed logger and output something if it's enabled.
private void DebugLog(string msg, params Object[] args)
{
m_scene.Logger.DebugFormat(msg, args);
}
// Invoke the detailed logger and output something if it's enabled.
private void DetailLog(string msg, params Object[] args)
{
m_scene.PhysicsLogging.Write(msg, args);
}
}
}

View File

@ -66,7 +66,7 @@ public sealed class BSPrim : PhysicsActor
private bool _isSelected; private bool _isSelected;
private bool _isVolumeDetect; private bool _isVolumeDetect;
private OMV.Vector3 _position; private OMV.Vector3 _position;
private float _mass; private float _mass; // the mass of this object
private float _density; private float _density;
private OMV.Vector3 _force; private OMV.Vector3 _force;
private OMV.Vector3 _velocity; private OMV.Vector3 _velocity;
@ -89,8 +89,13 @@ public sealed class BSPrim : PhysicsActor
private bool _kinematic; private bool _kinematic;
private float _buoyancy; private float _buoyancy;
private BSPrim _parentPrim; // Membership in a linkset is controlled by this class.
private List<BSPrim> _childrenPrims; private BSLinkset _linkset;
public BSLinkset Linkset
{
get { return _linkset; }
set { _linkset = value; }
}
private int _subscribedEventsMs = 0; private int _subscribedEventsMs = 0;
private int _nextCollisionOkTime = 0; private int _nextCollisionOkTime = 0;
@ -133,9 +138,8 @@ public sealed class BSPrim : PhysicsActor
_friction = _scene.Params.defaultFriction; // TODO: compute based on object material _friction = _scene.Params.defaultFriction; // TODO: compute based on object material
_density = _scene.Params.defaultDensity; // TODO: compute based on object material _density = _scene.Params.defaultDensity; // TODO: compute based on object material
_restitution = _scene.Params.defaultRestitution; _restitution = _scene.Params.defaultRestitution;
_parentPrim = null; // not a child or a parent _linkset = new BSLinkset(_scene, this); // a linkset of one
_vehicle = new BSDynamics(this); // add vehicleness _vehicle = new BSDynamics(this); // add vehicleness
_childrenPrims = new List<BSPrim>();
_mass = CalculateMass(); _mass = CalculateMass();
// do the actual object creation at taint time // do the actual object creation at taint time
_scene.TaintedObject(delegate() _scene.TaintedObject(delegate()
@ -161,16 +165,8 @@ public sealed class BSPrim : PhysicsActor
_scene.TaintedObject(delegate() _scene.TaintedObject(delegate()
{ {
// undo any dependance with/on other objects // Undo any links between me and any other object
if (_parentPrim != null) _linkset = _linkset.RemoveMeFromLinkset(this);
{
// If I'm someone's child, tell them to forget about me.
_parentPrim.RemoveChildFromLinkset(this);
_parentPrim = null;
}
// make sure there are no other prims linked to me
UnlinkAllChildren();
// everything in the C# world will get garbage collected. Tell the C++ world to free stuff. // everything in the C# world will get garbage collected. Tell the C++ world to free stuff.
BulletSimAPI.DestroyObject(_scene.WorldID, LocalID); BulletSimAPI.DestroyObject(_scene.WorldID, LocalID);
@ -187,7 +183,7 @@ public sealed class BSPrim : PhysicsActor
_scene.TaintedObject(delegate() _scene.TaintedObject(delegate()
{ {
_mass = CalculateMass(); // changing size changes the mass _mass = CalculateMass(); // changing size changes the mass
BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, Mass, IsPhysical); BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, (IsPhysical ? _mass : 0f), IsPhysical);
RecreateGeomAndObject(); RecreateGeomAndObject();
}); });
} }
@ -226,32 +222,8 @@ public sealed class BSPrim : PhysicsActor
BSPrim parent = obj as BSPrim; BSPrim parent = obj as BSPrim;
DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID); DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID);
DetailLog("{0},link,parent={1}", LocalID, obj.LocalID); DetailLog("{0},link,parent={1}", LocalID, obj.LocalID);
// TODO: decide if this parent checking needs to happen at taint time
if (_parentPrim == null) _linkset = _linkset.AddMeToLinkset(this, parent);
{
if (parent != null)
{
// I don't have a parent so I am joining a linkset
parent.AddChildToLinkset(this);
}
}
else
{
// I already have a parent, is parenting changing?
if (parent != _parentPrim)
{
if (parent == null)
{
// we are being removed from a linkset
_parentPrim.RemoveChildFromLinkset(this);
}
else
{
// asking to reparent a prim should not happen
m_log.ErrorFormat("{0}: link(): Reparenting a prim. ", LogHeader);
}
}
}
return; return;
} }
@ -260,81 +232,18 @@ public sealed class BSPrim : PhysicsActor
// TODO: decide if this parent checking needs to happen at taint time // TODO: decide if this parent checking needs to happen at taint time
// Race condition here: if link() and delink() in same simulation tick, the delink will not happen // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID, DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID,
(_parentPrim==null ? "NULL" : _parentPrim._avName+"/"+_parentPrim.LocalID.ToString())); _linkset.Root._avName+"/"+_linkset.Root.LocalID.ToString());
DetailLog("{0},delink,parent={1}", LocalID, (_parentPrim==null ? "NULL" : _parentPrim.LocalID.ToString())); DetailLog("{0},delink,parent={1}", LocalID, _linkset.Root.LocalID.ToString());
if (_parentPrim != null)
{ _linkset.RemoveMeFromLinkset(this);
_parentPrim.RemoveChildFromLinkset(this);
}
return; return;
} }
// I am the root of a linkset and a new child is being added
public void AddChildToLinkset(BSPrim pchild)
{
BSPrim child = pchild;
_scene.TaintedObject(delegate()
{
if (!_childrenPrims.Contains(child))
{
DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, this.LocalID);
DetailLog("{0},AddChildToLinkset,child={1}", LocalID, pchild.LocalID);
_childrenPrims.Add(child);
child._parentPrim = this; // the child has gained a parent
// RecreateGeomAndObject(); // rebuild my shape with the new child added
LinkAChildToMe(pchild); // build the physical binding between me and the child
_mass = CalculateMass();
}
});
return;
}
// I am the root of a linkset and one of my children is being removed.
// Safe to call even if the child is not really in my linkset.
public void RemoveChildFromLinkset(BSPrim pchild)
{
BSPrim child = pchild;
_scene.TaintedObject(delegate()
{
if (_childrenPrims.Contains(child))
{
DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID);
DetailLog("{0},RemoveChildFromLinkset,child={1}", LocalID, pchild.LocalID);
_childrenPrims.Remove(child);
child._parentPrim = null; // the child has lost its parent
if (_childrenPrims.Count == 0)
{
// if the linkset is empty, make sure all linkages have been removed
UnlinkAllChildren();
}
else
{
// RecreateGeomAndObject(); // rebuild my shape with the child removed
UnlinkAChildFromMe(pchild);
}
_mass = CalculateMass();
}
else
{
m_log.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset");
}
});
return;
}
// return true if we are the root of a linkset (there are children to manage)
public bool IsRootOfLinkset
{
get { return (_parentPrim == null && _childrenPrims.Count != 0); }
}
// Set motion values to zero. // Set motion values to zero.
// Do it to the properties so the values get set in the physics engine. // Do it to the properties so the values get set in the physics engine.
// Push the setting of the values to the viewer. // Push the setting of the values to the viewer.
// Called at taint time! // Called at taint time!
private void ZeroMotion() public void ZeroMotion()
{ {
_velocity = OMV.Vector3.Zero; _velocity = OMV.Vector3.Zero;
_acceleration = OMV.Vector3.Zero; _acceleration = OMV.Vector3.Zero;
@ -355,9 +264,10 @@ public sealed class BSPrim : PhysicsActor
public override OMV.Vector3 Position { public override OMV.Vector3 Position {
get { get {
if (!_linkset.IsRoot(this))
// child prims move around based on their parent. Need to get the latest location // child prims move around based on their parent. Need to get the latest location
if (_parentPrim != null)
_position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
// don't do the GetObjectPosition for root elements because this function is called a zillion times // 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; return _position;
@ -373,16 +283,31 @@ public sealed class BSPrim : PhysicsActor
} }
} }
// Return the effective mass of the object. Non-physical objects do not have mass. // Return the effective mass of the object.
public override float Mass { // If there are multiple items in the linkset, add them together for the root
get { public override float Mass
if (IsPhysical) {
return _mass; get
else {
return 0f; return _linkset.Mass;
} }
} }
// used when we only want this prim's mass and not the linkset thing
public float MassRaw { get { return _mass; } }
// Is this used?
public override OMV.Vector3 CenterOfMass
{
get { return _linkset.CenterOfMass; }
}
// Is this used?
public override OMV.Vector3 GeometricCenter
{
get { return _linkset.GeometricCenter; }
}
public override OMV.Vector3 Force { public override OMV.Vector3 Force {
get { return _force; } get { return _force; }
set { set {
@ -473,8 +398,6 @@ public sealed class BSPrim : PhysicsActor
return; return;
} }
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 { public override OMV.Vector3 Velocity {
get { return _velocity; } get { return _velocity; }
set { set {
@ -503,9 +426,9 @@ public sealed class BSPrim : PhysicsActor
} }
public override OMV.Quaternion Orientation { public override OMV.Quaternion Orientation {
get { get {
if (_parentPrim != null) if (!_linkset.IsRoot(this))
{ {
// children move around because tied to parent. Get a fresh value. // Children move around because tied to parent. Get a fresh value.
_orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID); _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID);
} }
return _orientation; return _orientation;
@ -555,14 +478,16 @@ public sealed class BSPrim : PhysicsActor
private void SetObjectDynamic() private void SetObjectDynamic()
{ {
// m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid); // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid);
// non-physical things work best with a mass of zero
if (!IsStatic)
{
_mass = CalculateMass();
RecreateGeomAndObject(); RecreateGeomAndObject();
}
DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, Mass); float mass = _mass;
BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), Mass); // Bullet wants static objects have a mass of zero
if (IsStatic)
mass = 0f;
DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, mass);
BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass);
} }
// prims don't fly // prims don't fly
@ -1004,6 +929,9 @@ public sealed class BSPrim : PhysicsActor
returnMass = _density * volume; returnMass = _density * volume;
/*
* This change means each object keeps its own mass and the Mass property
* will return the sum if we're part of a linkset.
if (IsRootOfLinkset) if (IsRootOfLinkset)
{ {
foreach (BSPrim prim in _childrenPrims) foreach (BSPrim prim in _childrenPrims)
@ -1011,6 +939,7 @@ public sealed class BSPrim : PhysicsActor
returnMass += prim.CalculateMass(); returnMass += prim.CalculateMass();
} }
} }
*/
if (returnMass <= 0) if (returnMass <= 0)
returnMass = 0.0001f; returnMass = 0.0001f;
@ -1026,9 +955,11 @@ public sealed class BSPrim : PhysicsActor
// The objects needs a hull if it's physical otherwise a mesh is enough // The objects needs a hull if it's physical otherwise a mesh is enough
// No locking here because this is done when we know physics is not simulating // No locking here because this is done when we know physics is not simulating
// if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used
private void CreateGeom(bool forceRebuild) // Returns 'true' if the geometry was rebuilt
private bool CreateGeom(bool forceRebuild)
{ {
// the mesher thought this was too simple to mesh. Use a native Bullet collision shape. // the mesher thought this was too simple to mesh. Use a native Bullet collision shape.
bool ret = false;
if (!_scene.NeedsMeshing(_pbs)) if (!_scene.NeedsMeshing(_pbs))
{ {
if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
@ -1036,20 +967,28 @@ public sealed class BSPrim : PhysicsActor
if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
{ {
// m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size); // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size);
_shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; if (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE)
{
DetailLog("{0},CreateGeom,sphere", LocalID); DetailLog("{0},CreateGeom,sphere", LocalID);
_shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
ret = true;
// Bullet native objects are scaled by the Bullet engine so pass the size in // Bullet native objects are scaled by the Bullet engine so pass the size in
_scale = _size; _scale = _size;
} }
} }
}
else else
{ {
// m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size); // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size);
if (_shapeType != ShapeData.PhysicsShapeType.SHAPE_BOX)
{
DetailLog("{0},CreateGeom,box", LocalID); DetailLog("{0},CreateGeom,box", LocalID);
_shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
ret = true;
_scale = _size; _scale = _size;
} }
} }
}
else else
{ {
if (IsPhysical) if (IsPhysical)
@ -1059,6 +998,7 @@ public sealed class BSPrim : PhysicsActor
// physical objects require a hull for interaction. // physical objects require a hull for interaction.
// This will create the mesh if it doesn't already exist // This will create the mesh if it doesn't already exist
CreateGeomHull(); CreateGeomHull();
ret = true;
} }
} }
else else
@ -1067,9 +1007,11 @@ public sealed class BSPrim : PhysicsActor
{ {
// Static (non-physical) objects only need a mesh for bumping into // Static (non-physical) objects only need a mesh for bumping into
CreateGeomMesh(); CreateGeomMesh();
ret = true;
} }
} }
} }
return ret;
} }
// No locking here because this is done when we know physics is not simulating // No locking here because this is done when we know physics is not simulating
@ -1254,20 +1196,18 @@ public sealed class BSPrim : PhysicsActor
// No locking here because this is done when the physics engine is not simulating // No locking here because this is done when the physics engine is not simulating
private void CreateObject() private void CreateObject()
{ {
if (IsRootOfLinkset) // this routine is called when objects are rebuilt.
{
// Create a linkset around this object
CreateLinkset();
}
else
{
// simple object
// the mesh or hull must have already been created in Bullet // the mesh or hull must have already been created in Bullet
ShapeData shape; ShapeData shape;
FillShapeInfo(out shape); FillShapeInfo(out shape);
// m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type); // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type);
BulletSimAPI.CreateObject(_scene.WorldID, shape); BulletSimAPI.CreateObject(_scene.WorldID, shape);
} // the CreateObject() may have recreated the rigid body. Make sure we have the latest.
m_body.Ptr = BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID);
// The root object could have been recreated. Make sure everything linksety is up to date.
_linkset.RefreshLinkset(this);
} }
// Copy prim's info into the BulletSim shape description structure // Copy prim's info into the BulletSim shape description structure
@ -1279,7 +1219,7 @@ public sealed class BSPrim : PhysicsActor
shape.Rotation = _orientation; shape.Rotation = _orientation;
shape.Velocity = _velocity; shape.Velocity = _velocity;
shape.Scale = _scale; shape.Scale = _scale;
shape.Mass = Mass; shape.Mass = _isPhysical ? _mass : 0f;
shape.Buoyancy = _buoyancy; shape.Buoyancy = _buoyancy;
shape.HullKey = _hullKey; shape.HullKey = _hullKey;
shape.MeshKey = _meshKey; shape.MeshKey = _meshKey;
@ -1289,83 +1229,6 @@ public sealed class BSPrim : PhysicsActor
shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
} }
#region Linkset creation and destruction
// Create the linkset by putting constraints between the objects of the set so they cannot move
// relative to each other.
void CreateLinkset()
{
// DebugLog("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1);
// remove any constraints that might be in place
UnlinkAllChildren();
// create constraints between the root prim and each of the children
foreach (BSPrim prim in _childrenPrims)
{
LinkAChildToMe(prim);
}
}
// Create a constraint between me (root of linkset) and the passed prim (the child).
// Called at taint time!
private void LinkAChildToMe(BSPrim childPrim)
{
// Zero motion for children so they don't interpolate
childPrim.ZeroMotion();
// relative position normalized to the root prim
OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(this._orientation);
OMV.Vector3 childRelativePosition = (childPrim._position - this._position) * invThisOrientation;
// relative rotation of the child to the parent
OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim._orientation;
// create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
// DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID);
DetailLog("{0},LinkAChildToMe,taint,root={1},child={2}", LocalID, LocalID, childPrim.LocalID);
BSConstraint constrain = _scene.Constraints.CreateConstraint(
_scene.World, this.Body, childPrim.Body,
childRelativePosition,
childRelativeRotation,
OMV.Vector3.Zero,
OMV.Quaternion.Identity);
constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
// tweek the constraint to increase stability
constrain.UseFrameOffset(_scene.BoolNumeric(_scene.Params.linkConstraintUseFrameOffset));
if (_scene.BoolNumeric(_scene.Params.linkConstraintEnableTransMotor))
{
constrain.TranslationalLimitMotor(true,
_scene.Params.linkConstraintTransMotorMaxVel,
_scene.Params.linkConstraintTransMotorMaxForce);
}
}
// Remove linkage between myself and a particular child
// Called at taint time!
private void UnlinkAChildFromMe(BSPrim childPrim)
{
DebugLog("{0}: UnlinkAChildFromMe: RemoveConstraint between root prim {1} and child prim {2}",
LogHeader, LocalID, childPrim.LocalID);
DetailLog("{0},UnlinkAChildFromMe,taint,root={1},child={2}", LocalID, LocalID, childPrim.LocalID);
// BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, childPrim.LocalID);
_scene.Constraints.RemoveAndDestroyConstraint(this.Body, childPrim.Body);
}
// Remove linkage between myself and any possible children I might have
// Called at taint time!
private void UnlinkAllChildren()
{
DebugLog("{0}: UnlinkAllChildren:", LogHeader);
DetailLog("{0},UnlinkAllChildren,taint", LocalID);
_scene.Constraints.RemoveAndDestroyConstraint(this.Body);
// BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID);
}
#endregion // Linkset creation and destruction
// Rebuild the geometry and object. // Rebuild the geometry and object.
// This is called when the shape changes so we need to recreate the mesh/hull. // This is called when the shape changes so we need to recreate the mesh/hull.
@ -1443,7 +1306,7 @@ public sealed class BSPrim : PhysicsActor
// Don't check for damping here -- it's done in BulletSim and SceneObjectPart. // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
// Updates only for individual prims and for the root object of a linkset. // Updates only for individual prims and for the root object of a linkset.
if (_parentPrim == null) if (_linkset.IsRoot(this))
{ {
// Assign to the local variables so the normal set action does not happen // Assign to the local variables so the normal set action does not happen
_position = entprop.Position; _position = entprop.Position;

View File

@ -73,7 +73,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[BULLETS SCENE]"; private static readonly string LogHeader = "[BULLETS SCENE]";
private void DebugLog(string mm, params Object[] xx) { if (shouldDebugLog) m_log.DebugFormat(mm, xx); } public void DebugLog(string mm, params Object[] xx) { if (shouldDebugLog) m_log.DebugFormat(mm, xx); }
public string BulletSimVersion = "?"; public string BulletSimVersion = "?";
@ -87,6 +87,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private uint m_worldID; private uint m_worldID;
public uint WorldID { get { return m_worldID; } } public uint WorldID { get { return m_worldID; } }
// let my minuions use my logger
public ILog Logger { get { return m_log; } }
private bool m_initialized = false; private bool m_initialized = false;
private int m_detailedStatsStep = 0; private int m_detailedStatsStep = 0;
@ -1026,7 +1029,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ), (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
ConfigurationParameters.numericTrue, ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].linkConstraintUseFrameOffset; }, (s) => { return s.m_params[0].linkConstraintUseFrameOffset; },
(s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ), (s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ),

View File

@ -239,10 +239,10 @@ public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool CreateObject(uint worldID, ShapeData shapeData); public static extern bool CreateObject(uint worldID, ShapeData shapeData);
/* Remove old functionality
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas); public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas);
/* Remove old functionality
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void AddConstraint(uint worldID, uint id1, uint id2, public static extern void AddConstraint(uint worldID, uint id1, uint id2,
Vector3 frame1, Quaternion frame1rot, Vector3 frame1, Quaternion frame1rot,

View File

@ -915,7 +915,7 @@
NumberOfSolverIterations = 0; NumberOfSolverIterations = 0;
; Linkset constraint parameters ; Linkset constraint parameters
LinkConstraintUseFrameOffset = True; LinkConstraintUseFrameOffset = False;
LinkConstraintEnableTransMotor = True; LinkConstraintEnableTransMotor = True;
LinkConstraintTransMotorMaxVel = 5.0; LinkConstraintTransMotorMaxVel = 5.0;
LinkConstraintTransMotorMaxForce = 0.1; LinkConstraintTransMotorMaxForce = 0.1;
@ -937,7 +937,7 @@
FixedTimeStep = .01667 FixedTimeStep = .01667
MaxCollisionsPerFrame = 2048 MaxCollisionsPerFrame = 2048
MaxUpdatesPerFrame = 2048 MaxUpdatesPerFrame = 8192
[RemoteAdmin] [RemoteAdmin]
enabled = false enabled = false