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
parent
d4a667a918
commit
7d30637d51
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -66,7 +66,7 @@ public sealed class BSPrim : PhysicsActor
|
|||
private bool _isSelected;
|
||||
private bool _isVolumeDetect;
|
||||
private OMV.Vector3 _position;
|
||||
private float _mass;
|
||||
private float _mass; // the mass of this object
|
||||
private float _density;
|
||||
private OMV.Vector3 _force;
|
||||
private OMV.Vector3 _velocity;
|
||||
|
@ -89,8 +89,13 @@ public sealed class BSPrim : PhysicsActor
|
|||
private bool _kinematic;
|
||||
private float _buoyancy;
|
||||
|
||||
private BSPrim _parentPrim;
|
||||
private List<BSPrim> _childrenPrims;
|
||||
// Membership in a linkset is controlled by this class.
|
||||
private BSLinkset _linkset;
|
||||
public BSLinkset Linkset
|
||||
{
|
||||
get { return _linkset; }
|
||||
set { _linkset = value; }
|
||||
}
|
||||
|
||||
private int _subscribedEventsMs = 0;
|
||||
private int _nextCollisionOkTime = 0;
|
||||
|
@ -133,9 +138,8 @@ public sealed class BSPrim : PhysicsActor
|
|||
_friction = _scene.Params.defaultFriction; // TODO: compute based on object material
|
||||
_density = _scene.Params.defaultDensity; // TODO: compute based on object material
|
||||
_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
|
||||
_childrenPrims = new List<BSPrim>();
|
||||
_mass = CalculateMass();
|
||||
// do the actual object creation at taint time
|
||||
_scene.TaintedObject(delegate()
|
||||
|
@ -161,16 +165,8 @@ public sealed class BSPrim : PhysicsActor
|
|||
|
||||
_scene.TaintedObject(delegate()
|
||||
{
|
||||
// undo any dependance with/on other objects
|
||||
if (_parentPrim != null)
|
||||
{
|
||||
// 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();
|
||||
// Undo any links between me and any other object
|
||||
_linkset = _linkset.RemoveMeFromLinkset(this);
|
||||
|
||||
// everything in the C# world will get garbage collected. Tell the C++ world to free stuff.
|
||||
BulletSimAPI.DestroyObject(_scene.WorldID, LocalID);
|
||||
|
@ -187,7 +183,7 @@ public sealed class BSPrim : PhysicsActor
|
|||
_scene.TaintedObject(delegate()
|
||||
{
|
||||
_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();
|
||||
});
|
||||
}
|
||||
|
@ -226,32 +222,8 @@ public sealed class BSPrim : PhysicsActor
|
|||
BSPrim parent = obj as BSPrim;
|
||||
DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_linkset = _linkset.AddMeToLinkset(this, parent);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -260,81 +232,18 @@ public sealed class BSPrim : PhysicsActor
|
|||
// 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
|
||||
DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID,
|
||||
(_parentPrim==null ? "NULL" : _parentPrim._avName+"/"+_parentPrim.LocalID.ToString()));
|
||||
DetailLog("{0},delink,parent={1}", LocalID, (_parentPrim==null ? "NULL" : _parentPrim.LocalID.ToString()));
|
||||
if (_parentPrim != null)
|
||||
{
|
||||
_parentPrim.RemoveChildFromLinkset(this);
|
||||
}
|
||||
_linkset.Root._avName+"/"+_linkset.Root.LocalID.ToString());
|
||||
DetailLog("{0},delink,parent={1}", LocalID, _linkset.Root.LocalID.ToString());
|
||||
|
||||
_linkset.RemoveMeFromLinkset(this);
|
||||
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.
|
||||
// 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!
|
||||
private void ZeroMotion()
|
||||
public void ZeroMotion()
|
||||
{
|
||||
_velocity = OMV.Vector3.Zero;
|
||||
_acceleration = OMV.Vector3.Zero;
|
||||
|
@ -355,9 +264,10 @@ public sealed class BSPrim : PhysicsActor
|
|||
|
||||
public override OMV.Vector3 Position {
|
||||
get {
|
||||
if (!_linkset.IsRoot(this))
|
||||
// child prims move around based on their parent. Need to get the latest location
|
||||
if (_parentPrim != null)
|
||||
_position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
|
||||
|
||||
// don't do the GetObjectPosition for root elements because this function is called a zillion times
|
||||
// _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
|
||||
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.
|
||||
public override float Mass {
|
||||
get {
|
||||
if (IsPhysical)
|
||||
return _mass;
|
||||
else
|
||||
return 0f;
|
||||
// Return the effective mass of the object.
|
||||
// If there are multiple items in the linkset, add them together for the root
|
||||
public override float Mass
|
||||
{
|
||||
get
|
||||
{
|
||||
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 {
|
||||
get { return _force; }
|
||||
set {
|
||||
|
@ -473,8 +398,6 @@ public sealed class BSPrim : PhysicsActor
|
|||
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 {
|
||||
get { return _velocity; }
|
||||
set {
|
||||
|
@ -503,9 +426,9 @@ public sealed class BSPrim : PhysicsActor
|
|||
}
|
||||
public override OMV.Quaternion Orientation {
|
||||
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);
|
||||
}
|
||||
return _orientation;
|
||||
|
@ -555,14 +478,16 @@ public sealed class BSPrim : PhysicsActor
|
|||
private void SetObjectDynamic()
|
||||
{
|
||||
// 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();
|
||||
}
|
||||
DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, Mass);
|
||||
BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), Mass);
|
||||
|
||||
float mass = _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
|
||||
|
@ -1004,6 +929,9 @@ public sealed class BSPrim : PhysicsActor
|
|||
|
||||
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)
|
||||
{
|
||||
foreach (BSPrim prim in _childrenPrims)
|
||||
|
@ -1011,6 +939,7 @@ public sealed class BSPrim : PhysicsActor
|
|||
returnMass += prim.CalculateMass();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (returnMass <= 0)
|
||||
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
|
||||
// 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
|
||||
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.
|
||||
bool ret = false;
|
||||
if (!_scene.NeedsMeshing(_pbs))
|
||||
{
|
||||
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)
|
||||
{
|
||||
// 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);
|
||||
_shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
|
||||
ret = true;
|
||||
// Bullet native objects are scaled by the Bullet engine so pass the size in
|
||||
_scale = _size;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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);
|
||||
_shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
|
||||
ret = true;
|
||||
_scale = _size;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsPhysical)
|
||||
|
@ -1059,6 +998,7 @@ public sealed class BSPrim : PhysicsActor
|
|||
// physical objects require a hull for interaction.
|
||||
// This will create the mesh if it doesn't already exist
|
||||
CreateGeomHull();
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1067,9 +1007,11 @@ public sealed class BSPrim : PhysicsActor
|
|||
{
|
||||
// Static (non-physical) objects only need a mesh for bumping into
|
||||
CreateGeomMesh();
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 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
|
||||
private void CreateObject()
|
||||
{
|
||||
if (IsRootOfLinkset)
|
||||
{
|
||||
// Create a linkset around this object
|
||||
CreateLinkset();
|
||||
}
|
||||
else
|
||||
{
|
||||
// simple object
|
||||
// this routine is called when objects are rebuilt.
|
||||
|
||||
// the mesh or hull must have already been created in Bullet
|
||||
ShapeData shape;
|
||||
FillShapeInfo(out shape);
|
||||
// m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type);
|
||||
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
|
||||
|
@ -1279,7 +1219,7 @@ public sealed class BSPrim : PhysicsActor
|
|||
shape.Rotation = _orientation;
|
||||
shape.Velocity = _velocity;
|
||||
shape.Scale = _scale;
|
||||
shape.Mass = Mass;
|
||||
shape.Mass = _isPhysical ? _mass : 0f;
|
||||
shape.Buoyancy = _buoyancy;
|
||||
shape.HullKey = _hullKey;
|
||||
shape.MeshKey = _meshKey;
|
||||
|
@ -1289,83 +1229,6 @@ public sealed class BSPrim : PhysicsActor
|
|||
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.
|
||||
// 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.
|
||||
|
||||
// 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
|
||||
_position = entprop.Position;
|
||||
|
|
|
@ -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 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 = "?";
|
||||
|
||||
|
@ -87,6 +87,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
private uint 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 int m_detailedStatsStep = 0;
|
||||
|
@ -1026,7 +1029,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
(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.",
|
||||
ConfigurationParameters.numericTrue,
|
||||
ConfigurationParameters.numericFalse,
|
||||
(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,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ),
|
||||
|
|
|
@ -239,10 +239,10 @@ public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey);
|
|||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern bool CreateObject(uint worldID, ShapeData shapeData);
|
||||
|
||||
/* Remove old functionality
|
||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas);
|
||||
|
||||
/* Remove old functionality
|
||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern void AddConstraint(uint worldID, uint id1, uint id2,
|
||||
Vector3 frame1, Quaternion frame1rot,
|
||||
|
|
|
@ -915,7 +915,7 @@
|
|||
NumberOfSolverIterations = 0;
|
||||
|
||||
; Linkset constraint parameters
|
||||
LinkConstraintUseFrameOffset = True;
|
||||
LinkConstraintUseFrameOffset = False;
|
||||
LinkConstraintEnableTransMotor = True;
|
||||
LinkConstraintTransMotorMaxVel = 5.0;
|
||||
LinkConstraintTransMotorMaxForce = 0.1;
|
||||
|
@ -937,7 +937,7 @@
|
|||
FixedTimeStep = .01667
|
||||
|
||||
MaxCollisionsPerFrame = 2048
|
||||
MaxUpdatesPerFrame = 2048
|
||||
MaxUpdatesPerFrame = 8192
|
||||
|
||||
[RemoteAdmin]
|
||||
enabled = false
|
||||
|
|
Loading…
Reference in New Issue