BulletSim: complete code for managed code shape and body tracking. Not debugged.
Eliminate some null exceptions created adding the above code. Add and remove some detailed logging statements.connector_plugin
parent
a27e4ce6cb
commit
22290ef35a
|
@ -77,7 +77,7 @@ public class BSCharacter : BSPhysObject
|
||||||
|
|
||||||
public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
|
public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
|
||||||
{
|
{
|
||||||
base.BaseInitialize(parent_scene, localID, avName);
|
base.BaseInitialize(parent_scene, localID, avName, "BSCharacter");
|
||||||
_physicsActorType = (int)ActorTypes.Agent;
|
_physicsActorType = (int)ActorTypes.Agent;
|
||||||
_position = pos;
|
_position = pos;
|
||||||
_size = size;
|
_size = size;
|
||||||
|
|
|
@ -39,11 +39,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// unless the difference is significant.
|
// unless the difference is significant.
|
||||||
public abstract class BSPhysObject : PhysicsActor
|
public abstract class BSPhysObject : PhysicsActor
|
||||||
{
|
{
|
||||||
protected void BaseInitialize(BSScene parentScene, uint localID, string name)
|
protected void BaseInitialize(BSScene parentScene, uint localID, string name, string typeName)
|
||||||
{
|
{
|
||||||
PhysicsScene = parentScene;
|
PhysicsScene = parentScene;
|
||||||
LocalID = localID;
|
LocalID = localID;
|
||||||
PhysObjectName = name;
|
PhysObjectName = name;
|
||||||
|
TypeName = typeName;
|
||||||
|
|
||||||
Linkset = new BSLinkset(PhysicsScene, this);
|
Linkset = new BSLinkset(PhysicsScene, this);
|
||||||
|
|
||||||
|
@ -56,6 +57,7 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
public BSScene PhysicsScene { get; protected set; }
|
public BSScene PhysicsScene { get; protected set; }
|
||||||
// public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
|
// public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
|
||||||
public string PhysObjectName { get; protected set; }
|
public string PhysObjectName { get; protected set; }
|
||||||
|
public string TypeName { get; protected set; }
|
||||||
|
|
||||||
public BSLinkset Linkset { get; set; }
|
public BSLinkset Linkset { get; set; }
|
||||||
|
|
||||||
|
@ -63,9 +65,9 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
public abstract float MassRaw { get; }
|
public abstract float MassRaw { get; }
|
||||||
|
|
||||||
// Reference to the physical body (btCollisionObject) of this object
|
// Reference to the physical body (btCollisionObject) of this object
|
||||||
public BulletBody BSBody { get; protected set; }
|
public BulletBody BSBody;
|
||||||
// Reference to the physical shape (btCollisionShape) of this object
|
// Reference to the physical shape (btCollisionShape) of this object
|
||||||
public BulletShape BSShape { get; protected set; }
|
public BulletShape BSShape;
|
||||||
|
|
||||||
// Stop all physical motion.
|
// Stop all physical motion.
|
||||||
public abstract void ZeroMotion();
|
public abstract void ZeroMotion();
|
||||||
|
@ -116,13 +118,11 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
DetailLog("{0},BSPhysObject.Collison,call,with={1}", LocalID, collidingWith);
|
|
||||||
|
|
||||||
// if someone has subscribed for collision events....
|
// if someone has subscribed for collision events....
|
||||||
if (SubscribedEvents()) {
|
if (SubscribedEvents()) {
|
||||||
CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
|
CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
|
||||||
DetailLog("{0},BSPhysObject.Collison.AddCollider,call,with={1},point={2},normal={3},depth={4}",
|
// DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
|
||||||
LocalID, collidingWith, contactPoint, contactNormal, pentrationDepth);
|
// LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -147,7 +147,7 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
if (CollisionCollection.Count == 0)
|
if (CollisionCollection.Count == 0)
|
||||||
PhysicsScene.ObjectsWithNoMoreCollisions.Add(this);
|
PhysicsScene.ObjectsWithNoMoreCollisions.Add(this);
|
||||||
|
|
||||||
DetailLog("{0},SendCollisions.SendCollisionUpdate,call,numCollisions={1}", LocalID, CollisionCollection.Count);
|
// DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
|
||||||
base.SendCollisionUpdate(CollisionCollection);
|
base.SendCollisionUpdate(CollisionCollection);
|
||||||
|
|
||||||
// The collisionCollection structure is passed around in the simulator.
|
// The collisionCollection structure is passed around in the simulator.
|
||||||
|
@ -164,9 +164,8 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
{
|
{
|
||||||
// make sure first collision happens
|
// make sure first collision happens
|
||||||
NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
|
NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
|
||||||
DetailLog("{0},SubscribeEvents,call,ms={1}", LocalID, SubscribedEventsMs);
|
|
||||||
|
|
||||||
PhysicsScene.TaintedObject("BSPhysObject.SubscribeEvents", delegate()
|
PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
|
||||||
{
|
{
|
||||||
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
|
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
|
||||||
});
|
});
|
||||||
|
@ -179,8 +178,7 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
}
|
}
|
||||||
public override void UnSubscribeEvents() {
|
public override void UnSubscribeEvents() {
|
||||||
SubscribedEventsMs = 0;
|
SubscribedEventsMs = 0;
|
||||||
DetailLog("{0},UnSubscribeEvents,call", LocalID);
|
PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
|
||||||
PhysicsScene.TaintedObject("BSPhysObject.UnSubscribeEvents", delegate()
|
|
||||||
{
|
{
|
||||||
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
|
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
|
||||||
});
|
});
|
||||||
|
|
|
@ -96,7 +96,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
|
OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
|
// m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
|
||||||
base.BaseInitialize(parent_scene, localID, primName);
|
base.BaseInitialize(parent_scene, localID, primName, "BSPrim");
|
||||||
_physicsActorType = (int)ActorTypes.Prim;
|
_physicsActorType = (int)ActorTypes.Prim;
|
||||||
_position = pos;
|
_position = pos;
|
||||||
_size = size;
|
_size = size;
|
||||||
|
@ -115,17 +115,17 @@ public sealed class BSPrim : BSPhysObject
|
||||||
_restitution = PhysicsScene.Params.defaultRestitution;
|
_restitution = PhysicsScene.Params.defaultRestitution;
|
||||||
_vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
|
_vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
|
||||||
_mass = CalculateMass();
|
_mass = CalculateMass();
|
||||||
|
|
||||||
|
// No body or shape yet
|
||||||
|
BSBody = new BulletBody(LocalID, IntPtr.Zero);
|
||||||
|
BSShape = new BulletShape(IntPtr.Zero);
|
||||||
|
|
||||||
DetailLog("{0},BSPrim.constructor,call", LocalID);
|
DetailLog("{0},BSPrim.constructor,call", LocalID);
|
||||||
// do the actual object creation at taint time
|
// do the actual object creation at taint time
|
||||||
PhysicsScene.TaintedObject("BSPrim.create", delegate()
|
PhysicsScene.TaintedObject("BSPrim.create", delegate()
|
||||||
{
|
{
|
||||||
CreateGeomAndObject(true);
|
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(PhysicsScene.World.Ptr, LocalID));
|
|
||||||
BSShape = new BulletShape(BulletSimAPI.GetCollisionShape2(BSBody.Ptr));
|
|
||||||
CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(BSBody.Ptr);
|
CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(BSBody.Ptr);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -168,17 +168,24 @@ public sealed class BSPrim : BSPhysObject
|
||||||
// Since _size changed, the mesh needs to be rebuilt. If rebuilt, all the correct
|
// Since _size changed, the mesh needs to be rebuilt. If rebuilt, all the correct
|
||||||
// scale and margins are set.
|
// scale and margins are set.
|
||||||
CreateGeomAndObject(true);
|
CreateGeomAndObject(true);
|
||||||
DetailLog("{0}: BSPrim.setSize: size={1}, scale={2}, mass={3}, physical={4}", LocalID, _size, _scale, _mass, IsPhysical);
|
DetailLog("{0},BSPrim.setSize,size={1},scale={2},mass={3},physical={4}", LocalID, _size, _scale, _mass, IsPhysical);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Scale is what we set in the physics engine. It is different than 'size' in that
|
||||||
|
// 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
|
||||||
|
public OMV.Vector3 Scale
|
||||||
|
{
|
||||||
|
get { return _scale; }
|
||||||
|
set { _scale = value; }
|
||||||
|
}
|
||||||
public override PrimitiveBaseShape Shape {
|
public override PrimitiveBaseShape Shape {
|
||||||
set {
|
set {
|
||||||
_pbs = value;
|
_pbs = value;
|
||||||
PhysicsScene.TaintedObject("BSPrim.setShape", delegate()
|
PhysicsScene.TaintedObject("BSPrim.setShape", delegate()
|
||||||
{
|
{
|
||||||
_mass = CalculateMass(); // changing the shape changes the mass
|
_mass = CalculateMass(); // changing the shape changes the mass
|
||||||
CreateGeomAndObject(false);
|
CreateGeomAndObject(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +198,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
_isSelected = value;
|
_isSelected = value;
|
||||||
PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
|
PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
|
||||||
{
|
{
|
||||||
SetObjectDynamic();
|
SetObjectDynamic(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -371,7 +378,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
|
PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
|
DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
|
||||||
SetObjectDynamic();
|
SetObjectDynamic(true);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -433,7 +440,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
|
PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
|
DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
|
||||||
SetObjectDynamic();
|
SetObjectDynamic(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -445,7 +452,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
}
|
}
|
||||||
|
|
||||||
// An object is solid if it's not phantom and if it's not doing VolumeDetect
|
// An object is solid if it's not phantom and if it's not doing VolumeDetect
|
||||||
private bool IsSolid
|
public bool IsSolid
|
||||||
{
|
{
|
||||||
get { return !IsPhantom && !_isVolumeDetect; }
|
get { return !IsPhantom && !_isVolumeDetect; }
|
||||||
}
|
}
|
||||||
|
@ -457,21 +464,23 @@ public sealed class BSPrim : BSPhysObject
|
||||||
// isSolid: other objects bounce off of this object
|
// isSolid: other objects bounce off of this object
|
||||||
// isVolumeDetect: other objects pass through but can generate collisions
|
// isVolumeDetect: other objects pass through but can generate collisions
|
||||||
// collisionEvents: whether this object returns collision events
|
// collisionEvents: whether this object returns collision events
|
||||||
private void SetObjectDynamic()
|
private void SetObjectDynamic(bool forceRebuild)
|
||||||
{
|
{
|
||||||
|
#if CSHARP_BODY_MANAGEMENT
|
||||||
|
// Recreate the physical object if necessary
|
||||||
|
CreateGeomAndObject(forceRebuild);
|
||||||
|
#else
|
||||||
// If it's becoming dynamic, it will need hullness
|
// If it's becoming dynamic, it will need hullness
|
||||||
VerifyCorrectPhysicalShape();
|
VerifyCorrectPhysicalShape();
|
||||||
UpdatePhysicalParameters();
|
UpdatePhysicalParameters();
|
||||||
|
#endif // CSHARP_BODY_MANAGEMENT
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdatePhysicalParameters()
|
private void UpdatePhysicalParameters()
|
||||||
{
|
{
|
||||||
/*
|
DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape);
|
||||||
// Bullet wants static objects to have a mass of zero
|
|
||||||
float mass = IsStatic ? 0f : _mass;
|
|
||||||
|
|
||||||
BulletSimAPI.SetObjectProperties(Scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass);
|
// Mangling all the physical properties requires the object to be out of the physical world
|
||||||
*/
|
|
||||||
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.Ptr, BSBody.Ptr);
|
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.Ptr, BSBody.Ptr);
|
||||||
|
|
||||||
// Make solid or not (do things bounce off or pass through this object)
|
// Make solid or not (do things bounce off or pass through this object)
|
||||||
|
@ -517,8 +526,8 @@ public sealed class BSPrim : BSPhysObject
|
||||||
// There can be special things needed for implementing linksets
|
// There can be special things needed for implementing linksets
|
||||||
Linkset.MakeStatic(this);
|
Linkset.MakeStatic(this);
|
||||||
// The activation state is 'sleeping' so Bullet will not try to act on it
|
// 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);
|
// BulletSimAPI.ForceActivationState2(BSBody.Ptr, ActivationState.DISABLE_SIMULATION);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -560,8 +569,8 @@ public sealed class BSPrim : BSPhysObject
|
||||||
// the functions after this one set up the state of a possibly newly created collision body.
|
// the functions after this one set up the state of a possibly newly created collision body.
|
||||||
private void MakeSolid(bool makeSolid)
|
private void MakeSolid(bool makeSolid)
|
||||||
{
|
{
|
||||||
|
#if !CSHARP_BODY_MANAGEMENT
|
||||||
CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(BSBody.Ptr);
|
CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(BSBody.Ptr);
|
||||||
/*
|
|
||||||
if (makeSolid)
|
if (makeSolid)
|
||||||
{
|
{
|
||||||
if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
|
if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
|
||||||
|
@ -569,11 +578,16 @@ public sealed class BSPrim : BSPhysObject
|
||||||
// Solid things are made out of rigid bodies. Remove this old body from the world
|
// Solid things are made out of rigid bodies. Remove this old body from the world
|
||||||
// and use this shape in a new rigid body.
|
// and use this shape in a new rigid body.
|
||||||
BulletBody oldBody = BSBody;
|
BulletBody oldBody = BSBody;
|
||||||
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.Ptr, BSBody.Ptr);
|
// Zero out the pointer to the shape in the old body so the shape will not get freed
|
||||||
BSShape = new BulletShape(BulletSimAPI.GetCollisionShape2(BSBody.Ptr));
|
BSShape.Ptr = BulletSimAPI.GetCollisionShape2(oldBody.Ptr);
|
||||||
|
BulletSimAPI.SetCollisionShape2(PhysicsScene.World.Ptr, oldBody.Ptr, IntPtr.Zero);
|
||||||
|
// Get rid of the old body and remove it from BulletSim's object list
|
||||||
|
BulletSimAPI.DestroyObject(PhysicsScene.WorldID, LocalID);
|
||||||
|
|
||||||
|
// Create the new body with the shape
|
||||||
BSBody = new BulletBody(LocalID, BulletSimAPI.CreateBodyFromShape2(PhysicsScene.World.Ptr, BSShape.Ptr, _position, _orientation));
|
BSBody = new BulletBody(LocalID, BulletSimAPI.CreateBodyFromShape2(PhysicsScene.World.Ptr, BSShape.Ptr, _position, _orientation));
|
||||||
BulletSimAPI.DestroyObject2(PhysicsScene.World.Ptr, oldBody.Ptr);
|
BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
|
||||||
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.Ptr, BSBody.Ptr);
|
DetailLog("{0},BSPrim.MakeSolid:rigidBody,body={1},shape={2}", LocalID, BSBody, BSShape);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -583,23 +597,20 @@ public sealed class BSPrim : BSPhysObject
|
||||||
// Non-solid things are made out of ghost objects. Remove this old body from the world
|
// Non-solid things are made out of ghost objects. Remove this old body from the world
|
||||||
// and use this shape in a new rigid body.
|
// and use this shape in a new rigid body.
|
||||||
BulletBody oldBody = BSBody;
|
BulletBody oldBody = BSBody;
|
||||||
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.Ptr, BSBody.Ptr);
|
|
||||||
BSShape = new BulletShape(BulletSimAPI.GetCollisionShape2(BSBody.Ptr));
|
// Zero out the pointer to the shape in the old body so the shape will not get freed
|
||||||
|
BSShape.Ptr = BulletSimAPI.GetCollisionShape2(oldBody.Ptr);
|
||||||
|
BulletSimAPI.SetCollisionShape2(PhysicsScene.World.Ptr, oldBody.Ptr, IntPtr.Zero);
|
||||||
|
// Get rid of the old body and remove it from BulletSim's object list
|
||||||
|
BulletSimAPI.DestroyObject(PhysicsScene.WorldID, LocalID);
|
||||||
|
|
||||||
BSBody = new BulletBody(LocalID,
|
BSBody = new BulletBody(LocalID,
|
||||||
BulletSimAPI.CreateGhostFromShape2(PhysicsScene.World.Ptr, BSShape.Ptr, _position, _orientation));
|
BulletSimAPI.CreateGhostFromShape2(PhysicsScene.World.Ptr, BSShape.Ptr, _position, _orientation));
|
||||||
if (BSBody.Ptr == IntPtr.Zero)
|
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
|
||||||
{
|
DetailLog("{0},BSPrim.MakeGhostBody,body={1},shape={2}", LocalID, BSBody, BSShape);
|
||||||
m_log.ErrorFormat("{0} BSPrim.MakeSolid: failed creation of ghost object. LocalID=[1}", LogHeader, LocalID);
|
|
||||||
BSBody = oldBody;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BulletSimAPI.DestroyObject2(PhysicsScene.World.Ptr, oldBody.Ptr);
|
|
||||||
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.Ptr, BSBody.Ptr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
#endif
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn on or off the flag controlling whether collision events are returned to the simulator.
|
// Turn on or off the flag controlling whether collision events are returned to the simulator.
|
||||||
|
@ -1067,6 +1078,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
}// end CalculateMass
|
}// end CalculateMass
|
||||||
#endregion Mass Calculation
|
#endregion Mass Calculation
|
||||||
|
|
||||||
|
#if !CSHARP_BODY_MANAGEMENT
|
||||||
// Create the geometry information in Bullet for later use.
|
// Create the geometry information in Bullet for later use.
|
||||||
// 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.
|
||||||
|
@ -1095,6 +1107,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSPrim.CreateGeom,sphere (force={1}", LocalID, forceRebuild);
|
DetailLog("{0},BSPrim.CreateGeom,sphere (force={1}", LocalID, forceRebuild);
|
||||||
_shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
|
_shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
|
||||||
|
_meshKey = (ulong)ShapeData.FixedShapeKey.KEY_SPHERE;
|
||||||
// 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;
|
||||||
// TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
|
// TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
|
||||||
|
@ -1109,6 +1122,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSPrim.CreateGeom,box (force={1})", LocalID, forceRebuild);
|
DetailLog("{0},BSPrim.CreateGeom,box (force={1})", LocalID, forceRebuild);
|
||||||
_shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
|
_shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
|
||||||
|
_meshKey = (ulong)ShapeData.FixedShapeKey.KEY_BOX;
|
||||||
_scale = _size;
|
_scale = _size;
|
||||||
// TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
|
// TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
|
||||||
ret = true;
|
ret = true;
|
||||||
|
@ -1136,6 +1150,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1345,12 +1360,9 @@ public sealed class BSPrim : BSPhysObject
|
||||||
// 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);
|
||||||
bool ret = BulletSimAPI.CreateObject(PhysicsScene.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(PhysicsScene.World.Ptr, LocalID));
|
|
||||||
BSShape = new BulletShape(BulletSimAPI.GetCollisionShape2(BSBody.Ptr));
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
#endif // !CSHARP_BODY_MANAGEMENT
|
||||||
|
|
||||||
// Copy prim's info into the BulletSim shape description structure
|
// Copy prim's info into the BulletSim shape description structure
|
||||||
public void FillShapeInfo(out ShapeData shape)
|
public void FillShapeInfo(out ShapeData shape)
|
||||||
|
@ -1369,22 +1381,45 @@ public sealed class BSPrim : BSPhysObject
|
||||||
shape.Restitution = _restitution;
|
shape.Restitution = _restitution;
|
||||||
shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
|
shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
|
||||||
shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
|
shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
|
||||||
|
shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue;
|
||||||
|
shape.Size = _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
// 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 CreateGeomAndObject(bool forceRebuild)
|
private void CreateGeomAndObject(bool forceRebuild)
|
||||||
{
|
{
|
||||||
|
#if CSHARP_BODY_MANAGEMENT
|
||||||
|
ShapeData shapeData;
|
||||||
|
FillShapeInfo(out shapeData);
|
||||||
|
|
||||||
|
// Create the correct physical representation for this type of object.
|
||||||
|
// Updates BSBody and BSShape with the new information.
|
||||||
|
if (PhysicsScene.Shapes.GetBodyAndShape(forceRebuild, PhysicsScene.World, this, shapeData, _pbs))
|
||||||
|
{
|
||||||
|
// Make sure the properties are set on the new object
|
||||||
|
UpdatePhysicalParameters();
|
||||||
|
}
|
||||||
|
#else
|
||||||
// m_log.DebugFormat("{0}: CreateGeomAndObject. lID={1}, force={2}", LogHeader, LocalID, forceRebuild);
|
// m_log.DebugFormat("{0}: CreateGeomAndObject. lID={1}, force={2}", LogHeader, LocalID, forceRebuild);
|
||||||
// Create the geometry that will make up the object
|
// Create the geometry that will make up the object
|
||||||
if (CreateGeom(forceRebuild))
|
if (CreateGeom(forceRebuild))
|
||||||
{
|
{
|
||||||
// Create the object and place it into the world
|
// Create the object and place it into the world
|
||||||
CreateObject();
|
CreateObject();
|
||||||
|
|
||||||
|
// the CreateObject() may have recreated the rigid body. Make sure we have the latest address.
|
||||||
|
BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(PhysicsScene.World.Ptr, LocalID));
|
||||||
|
BSShape = new BulletShape(BulletSimAPI.GetCollisionShape2(BSBody.Ptr), _shapeType);
|
||||||
|
BSShape.shapeKey = _meshKey;
|
||||||
|
DetailLog("{0},BSPrim.CreateGeomAndObject,body={1},shape={2}", LocalID, BSBody, BSShape);
|
||||||
|
|
||||||
// Make sure the properties are set on the new object
|
// Make sure the properties are set on the new object
|
||||||
UpdatePhysicalParameters();
|
UpdatePhysicalParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CSHARP_BODY_MANAGEMENT
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Contributors, http://opensimulator.org/
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
*
|
*
|
||||||
|
@ -28,6 +28,9 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using OMV = OpenMetaverse;
|
using OMV = OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Region.Physics.Manager;
|
||||||
|
using OpenSim.Region.Physics.ConvexDecompositionDotNet;
|
||||||
|
|
||||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
|
@ -35,6 +38,26 @@ public class BSShapeCollection : IDisposable
|
||||||
{
|
{
|
||||||
protected BSScene PhysicsScene { get; set; }
|
protected BSScene PhysicsScene { get; set; }
|
||||||
|
|
||||||
|
private Object m_shapeActivityLock = new Object();
|
||||||
|
|
||||||
|
private struct MeshDesc
|
||||||
|
{
|
||||||
|
public IntPtr Ptr;
|
||||||
|
public int referenceCount;
|
||||||
|
public DateTime lastReferenced;
|
||||||
|
public IMesh meshData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct HullDesc
|
||||||
|
{
|
||||||
|
public IntPtr Ptr;
|
||||||
|
public int referenceCount;
|
||||||
|
public DateTime lastReferenced;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<ulong, MeshDesc> Meshes = new Dictionary<ulong, MeshDesc>();
|
||||||
|
private Dictionary<ulong, HullDesc> Hulls = new Dictionary<ulong, HullDesc>();
|
||||||
|
|
||||||
public BSShapeCollection(BSScene physScene)
|
public BSShapeCollection(BSScene physScene)
|
||||||
{
|
{
|
||||||
PhysicsScene = physScene;
|
PhysicsScene = physScene;
|
||||||
|
@ -44,6 +67,27 @@ public class BSShapeCollection : IDisposable
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called to update/change the body and shape for an object.
|
||||||
|
// First checks the shape and updates that if necessary then makes
|
||||||
|
// sure the body is of the right type.
|
||||||
|
// Return 'true' if either the body or the shape changed.
|
||||||
|
// Called at taint-time!!
|
||||||
|
public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
// Do we have the correct geometry for this type of object?
|
||||||
|
if (CreateGeom(forceRebuild, prim, shapeData, pbs))
|
||||||
|
{
|
||||||
|
// If we had to select a new shape geometry for the object,
|
||||||
|
// rebuild the body around it.
|
||||||
|
CreateObject(true, prim, PhysicsScene.World, prim.BSShape, shapeData);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// Track another user of a body
|
// Track another user of a body
|
||||||
public void ReferenceBody(BulletBody shape)
|
public void ReferenceBody(BulletBody shape)
|
||||||
{
|
{
|
||||||
|
@ -57,12 +101,445 @@ public class BSShapeCollection : IDisposable
|
||||||
// Track another user of the shape
|
// Track another user of the shape
|
||||||
public void ReferenceShape(BulletShape shape)
|
public void ReferenceShape(BulletShape shape)
|
||||||
{
|
{
|
||||||
|
ReferenceShape(shape, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track the datastructures and use count for a shape.
|
||||||
|
// When creating a hull, this is called first to reference the mesh
|
||||||
|
// and then again to reference the hull.
|
||||||
|
// Meshes and hulls for the same shape have the same hash key.
|
||||||
|
private void ReferenceShape(BulletShape shape, IMesh meshData)
|
||||||
|
{
|
||||||
|
switch (shape.type)
|
||||||
|
{
|
||||||
|
case ShapeData.PhysicsShapeType.SHAPE_MESH:
|
||||||
|
MeshDesc meshDesc;
|
||||||
|
if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
|
||||||
|
{
|
||||||
|
// There is an existing instance of this mesh.
|
||||||
|
meshDesc.referenceCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This is a new reference to a mesh
|
||||||
|
meshDesc.Ptr = shape.Ptr;
|
||||||
|
meshDesc.meshData = meshData;
|
||||||
|
meshDesc.referenceCount = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
meshDesc.lastReferenced = System.DateTime.Now;
|
||||||
|
Meshes[shape.shapeKey] = meshDesc;
|
||||||
|
break;
|
||||||
|
case ShapeData.PhysicsShapeType.SHAPE_HULL:
|
||||||
|
HullDesc hullDesc;
|
||||||
|
if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
|
||||||
|
{
|
||||||
|
// There is an existing instance of this mesh.
|
||||||
|
hullDesc.referenceCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This is a new reference to a mesh
|
||||||
|
hullDesc.Ptr = shape.Ptr;
|
||||||
|
hullDesc.referenceCount = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
hullDesc.lastReferenced = System.DateTime.Now;
|
||||||
|
Hulls[shape.shapeKey] = hullDesc;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release the usage of a shape
|
// Release the usage of a shape
|
||||||
public void DereferenceShape(BulletShape shape)
|
public void DereferenceShape(BulletShape shape)
|
||||||
{
|
{
|
||||||
|
switch (shape.type)
|
||||||
|
{
|
||||||
|
case ShapeData.PhysicsShapeType.SHAPE_HULL:
|
||||||
|
DereferenceHull(shape);
|
||||||
|
// Hulls also include a mesh
|
||||||
|
DereferenceMesh(shape);
|
||||||
|
break;
|
||||||
|
case ShapeData.PhysicsShapeType.SHAPE_MESH:
|
||||||
|
DereferenceMesh(shape);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count down the reference count for a mesh shape
|
||||||
|
private void DereferenceMesh(BulletShape shape)
|
||||||
|
{
|
||||||
|
MeshDesc meshDesc;
|
||||||
|
if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
|
||||||
|
{
|
||||||
|
meshDesc.referenceCount--;
|
||||||
|
// TODO: release the Bullet storage
|
||||||
|
meshDesc.lastReferenced = System.DateTime.Now;
|
||||||
|
Meshes[shape.shapeKey] = meshDesc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count down the reference count for a hull shape
|
||||||
|
private void DereferenceHull(BulletShape shape)
|
||||||
|
{
|
||||||
|
HullDesc hullDesc;
|
||||||
|
if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
|
||||||
|
{
|
||||||
|
hullDesc.referenceCount--;
|
||||||
|
// TODO: release the Bullet storage (aging old entries?)
|
||||||
|
hullDesc.lastReferenced = System.DateTime.Now;
|
||||||
|
Hulls[shape.shapeKey] = hullDesc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the geometry information in Bullet for later use.
|
||||||
|
// 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.
|
||||||
|
// Returns 'true' if the geometry was rebuilt.
|
||||||
|
// Called at taint-time!
|
||||||
|
private bool CreateGeom(bool forceRebuild, BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
bool haveShape = false;
|
||||||
|
bool nativeShapePossible = true;
|
||||||
|
|
||||||
|
BulletShape newShape = new BulletShape(IntPtr.Zero);
|
||||||
|
|
||||||
|
// If the object is dynamic, it must have a hull shape
|
||||||
|
if (prim.IsPhysical)
|
||||||
|
nativeShapePossible = false;
|
||||||
|
|
||||||
|
// If the prim attributes are simple, this could be a simple Bullet native shape
|
||||||
|
if (nativeShapePossible
|
||||||
|
&& ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
|
||||||
|
|| (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
|
||||||
|
&& pbs.ProfileHollow == 0
|
||||||
|
&& pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
|
||||||
|
&& pbs.PathBegin == 0 && pbs.PathEnd == 0
|
||||||
|
&& pbs.PathTaperX == 0 && pbs.PathTaperY == 0
|
||||||
|
&& pbs.PathScaleX == 100 && pbs.PathScaleY == 100
|
||||||
|
&& pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
|
||||||
|
{
|
||||||
|
if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
|
||||||
|
{
|
||||||
|
haveShape = true;
|
||||||
|
if (forceRebuild || (prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE))
|
||||||
|
{
|
||||||
|
DetailLog("{0},BSShapeCollection.CreateGeom,sphere (force={1}", prim.LocalID, forceRebuild);
|
||||||
|
newShape = AddNativeShapeToPrim(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE);
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, type={2}, size={3}", LogHeader, LocalID, _shapeType, _size);
|
||||||
|
haveShape = true;
|
||||||
|
if (forceRebuild || (prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX))
|
||||||
|
{
|
||||||
|
DetailLog("{0},BSShapeCollection.CreateGeom,box (force={1})", prim.LocalID, forceRebuild);
|
||||||
|
newShape = AddNativeShapeToPrim(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX);
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If a simple shape isn't happening, create a mesh and possibly a hull
|
||||||
|
if (!haveShape)
|
||||||
|
{
|
||||||
|
if (prim.IsPhysical)
|
||||||
|
{
|
||||||
|
if (forceRebuild || !Hulls.ContainsKey(prim.BSShape.shapeKey))
|
||||||
|
{
|
||||||
|
// physical objects require a hull for interaction.
|
||||||
|
// This also creates the mesh if it doesn't already exist
|
||||||
|
ret = CreateGeomHull(prim, shapeData, pbs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (forceRebuild || !Meshes.ContainsKey(prim.BSShape.shapeKey))
|
||||||
|
{
|
||||||
|
// Static (non-physical) objects only need a mesh for bumping into
|
||||||
|
ret = CreateGeomMesh(prim, shapeData, pbs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BulletShape AddNativeShapeToPrim(BSPrim prim, ShapeData shapeData, ShapeData.PhysicsShapeType shapeType)
|
||||||
|
{
|
||||||
|
BulletShape newShape;
|
||||||
|
|
||||||
|
// Bullet native objects are scaled by the Bullet engine so pass the size in
|
||||||
|
prim.Scale = shapeData.Size;
|
||||||
|
|
||||||
|
// release any previous shape
|
||||||
|
DereferenceShape(prim.BSShape);
|
||||||
|
|
||||||
|
MeshDesc existingShapeDesc;
|
||||||
|
if (Meshes.TryGetValue(shapeData.MeshKey, out existingShapeDesc))
|
||||||
|
{
|
||||||
|
// If there is an existing allocated shape, use it
|
||||||
|
newShape = new BulletShape(existingShapeDesc.Ptr, shapeType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Shape of this discriptioin is not allocated. Create new.
|
||||||
|
newShape = new BulletShape(
|
||||||
|
BulletSimAPI.BuildNativeShape2(PhysicsScene.World.Ptr,
|
||||||
|
(float)shapeType,
|
||||||
|
PhysicsScene.Params.collisionMargin,
|
||||||
|
prim.Scale),
|
||||||
|
shapeType);
|
||||||
|
}
|
||||||
|
newShape.shapeKey = shapeData.MeshKey;
|
||||||
|
ReferenceShape(newShape);
|
||||||
|
prim.BSShape = newShape;
|
||||||
|
return newShape;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No locking here because this is done when we know physics is not simulating
|
||||||
|
// Returns 'true' of a mesh was actually rebuild (we could also have one of these specs).
|
||||||
|
// Called at taint-time!
|
||||||
|
private bool CreateGeomMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs)
|
||||||
|
{
|
||||||
|
BulletShape newShape = new BulletShape(IntPtr.Zero);
|
||||||
|
|
||||||
|
// level of detail based on size and type of the object
|
||||||
|
float lod = PhysicsScene.MeshLOD;
|
||||||
|
if (pbs.SculptEntry)
|
||||||
|
lod = PhysicsScene.SculptLOD;
|
||||||
|
|
||||||
|
float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z));
|
||||||
|
if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
|
||||||
|
lod = PhysicsScene.MeshMegaPrimLOD;
|
||||||
|
|
||||||
|
ulong newMeshKey = (ulong)pbs.GetMeshKey(shapeData.Size, lod);
|
||||||
|
// m_log.DebugFormat("{0}: CreateGeomMesh: lID={1}, oldKey={2}, newKey={3}", LogHeader, LocalID, _meshKey, newMeshKey);
|
||||||
|
|
||||||
|
// if this new shape is the same as last time, don't recreate the mesh
|
||||||
|
if (prim.BSShape.shapeKey == newMeshKey) return false;
|
||||||
|
|
||||||
|
DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,key={1}", prim.LocalID, newMeshKey);
|
||||||
|
|
||||||
|
// Since we're recreating new, get rid of the reference to the previous shape
|
||||||
|
DereferenceShape(prim.BSShape);
|
||||||
|
|
||||||
|
IMesh meshData = null;
|
||||||
|
IntPtr meshPtr;
|
||||||
|
MeshDesc meshDesc;
|
||||||
|
if (Meshes.TryGetValue(newMeshKey, out meshDesc))
|
||||||
|
{
|
||||||
|
// If the mesh has already been built just use it.
|
||||||
|
meshPtr = meshDesc.Ptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// always pass false for physicalness as this creates some sort of bounding box which we don't need
|
||||||
|
meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, shapeData.Size, lod, false);
|
||||||
|
|
||||||
|
int[] indices = meshData.getIndexListAsInt();
|
||||||
|
List<OMV.Vector3> vertices = meshData.getVertexList();
|
||||||
|
|
||||||
|
float[] verticesAsFloats = new float[vertices.Count * 3];
|
||||||
|
int vi = 0;
|
||||||
|
foreach (OMV.Vector3 vv in vertices)
|
||||||
|
{
|
||||||
|
verticesAsFloats[vi++] = vv.X;
|
||||||
|
verticesAsFloats[vi++] = vv.Y;
|
||||||
|
verticesAsFloats[vi++] = vv.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
|
||||||
|
// LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
|
||||||
|
|
||||||
|
meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.Ptr,
|
||||||
|
indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
|
||||||
|
}
|
||||||
|
newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
|
||||||
|
newShape.shapeKey = newMeshKey;
|
||||||
|
|
||||||
|
ReferenceShape(newShape, meshData);
|
||||||
|
|
||||||
|
// meshes are already scaled by the meshmerizer
|
||||||
|
prim.Scale = new OMV.Vector3(1f, 1f, 1f);
|
||||||
|
prim.BSShape = newShape;
|
||||||
|
return true; // 'true' means a new shape has been added to this prim
|
||||||
|
}
|
||||||
|
|
||||||
|
// No locking here because this is done when we know physics is not simulating
|
||||||
|
// Returns 'true' of a mesh was actually rebuild (we could also have one of these specs).
|
||||||
|
List<ConvexResult> m_hulls;
|
||||||
|
private bool CreateGeomHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs)
|
||||||
|
{
|
||||||
|
BulletShape newShape;
|
||||||
|
|
||||||
|
float lod = pbs.SculptEntry ? PhysicsScene.SculptLOD : PhysicsScene.MeshLOD;
|
||||||
|
ulong newHullKey = (ulong)pbs.GetMeshKey(shapeData.Size, lod);
|
||||||
|
// m_log.DebugFormat("{0}: CreateGeomHull: lID={1}, oldKey={2}, newKey={3}", LogHeader, LocalID, _hullKey, newHullKey);
|
||||||
|
|
||||||
|
// if the hull hasn't changed, don't rebuild it
|
||||||
|
if (newHullKey == prim.BSShape.shapeKey) return false;
|
||||||
|
|
||||||
|
DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", prim.LocalID, newHullKey, newHullKey);
|
||||||
|
|
||||||
|
// remove references to any previous shape
|
||||||
|
DereferenceShape(prim.BSShape);
|
||||||
|
|
||||||
|
// Make sure the underlying mesh exists and is correct
|
||||||
|
// Since we're in the hull code, we know CreateGeomMesh() will not create a native shape.
|
||||||
|
CreateGeomMesh(prim, shapeData, pbs);
|
||||||
|
MeshDesc meshDesc = Meshes[newHullKey];
|
||||||
|
|
||||||
|
IntPtr hullPtr;
|
||||||
|
HullDesc hullDesc;
|
||||||
|
if (Hulls.TryGetValue(newHullKey, out hullDesc))
|
||||||
|
{
|
||||||
|
hullPtr = hullDesc.Ptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int[] indices = meshDesc.meshData.getIndexListAsInt();
|
||||||
|
List<OMV.Vector3> vertices = meshDesc.meshData.getVertexList();
|
||||||
|
|
||||||
|
//format conversion from IMesh format to DecompDesc format
|
||||||
|
List<int> convIndices = new List<int>();
|
||||||
|
List<float3> convVertices = new List<float3>();
|
||||||
|
for (int ii = 0; ii < indices.GetLength(0); ii++)
|
||||||
|
{
|
||||||
|
convIndices.Add(indices[ii]);
|
||||||
|
}
|
||||||
|
foreach (OMV.Vector3 vv in vertices)
|
||||||
|
{
|
||||||
|
convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup and do convex hull conversion
|
||||||
|
m_hulls = new List<ConvexResult>();
|
||||||
|
DecompDesc dcomp = new DecompDesc();
|
||||||
|
dcomp.mIndices = convIndices;
|
||||||
|
dcomp.mVertices = convVertices;
|
||||||
|
ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
|
||||||
|
// create the hull into the _hulls variable
|
||||||
|
convexBuilder.process(dcomp);
|
||||||
|
|
||||||
|
// Convert the vertices and indices for passing to unmanaged.
|
||||||
|
// The hull information is passed as a large floating point array.
|
||||||
|
// The format is:
|
||||||
|
// convHulls[0] = number of hulls
|
||||||
|
// convHulls[1] = number of vertices in first hull
|
||||||
|
// convHulls[2] = hull centroid X coordinate
|
||||||
|
// convHulls[3] = hull centroid Y coordinate
|
||||||
|
// convHulls[4] = hull centroid Z coordinate
|
||||||
|
// convHulls[5] = first hull vertex X
|
||||||
|
// convHulls[6] = first hull vertex Y
|
||||||
|
// convHulls[7] = first hull vertex Z
|
||||||
|
// convHulls[8] = second hull vertex X
|
||||||
|
// ...
|
||||||
|
// convHulls[n] = number of vertices in second hull
|
||||||
|
// convHulls[n+1] = second hull centroid X coordinate
|
||||||
|
// ...
|
||||||
|
//
|
||||||
|
// TODO: is is very inefficient. Someday change the convex hull generator to return
|
||||||
|
// data structures that do not need to be converted in order to pass to Bullet.
|
||||||
|
// And maybe put the values directly into pinned memory rather than marshaling.
|
||||||
|
int hullCount = m_hulls.Count;
|
||||||
|
int totalVertices = 1; // include one for the count of the hulls
|
||||||
|
foreach (ConvexResult cr in m_hulls)
|
||||||
|
{
|
||||||
|
totalVertices += 4; // add four for the vertex count and centroid
|
||||||
|
totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
|
||||||
|
}
|
||||||
|
float[] convHulls = new float[totalVertices];
|
||||||
|
|
||||||
|
convHulls[0] = (float)hullCount;
|
||||||
|
int jj = 1;
|
||||||
|
foreach (ConvexResult cr in m_hulls)
|
||||||
|
{
|
||||||
|
// copy vertices for index access
|
||||||
|
float3[] verts = new float3[cr.HullVertices.Count];
|
||||||
|
int kk = 0;
|
||||||
|
foreach (float3 ff in cr.HullVertices)
|
||||||
|
{
|
||||||
|
verts[kk++] = ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to the array one hull's worth of data
|
||||||
|
convHulls[jj++] = cr.HullIndices.Count;
|
||||||
|
convHulls[jj++] = 0f; // centroid x,y,z
|
||||||
|
convHulls[jj++] = 0f;
|
||||||
|
convHulls[jj++] = 0f;
|
||||||
|
foreach (int ind in cr.HullIndices)
|
||||||
|
{
|
||||||
|
convHulls[jj++] = verts[ind].x;
|
||||||
|
convHulls[jj++] = verts[ind].y;
|
||||||
|
convHulls[jj++] = verts[ind].z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// create the hull data structure in Bullet
|
||||||
|
// m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, LocalID, _hullKey, hullCount);
|
||||||
|
hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.Ptr, hullCount, convHulls);
|
||||||
|
}
|
||||||
|
newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
|
||||||
|
newShape.shapeKey = newHullKey;
|
||||||
|
|
||||||
|
ReferenceShape(newShape);
|
||||||
|
|
||||||
|
// meshes are already scaled by the meshmerizer
|
||||||
|
prim.Scale = new OMV.Vector3(1f, 1f, 1f);
|
||||||
|
prim.BSShape = newShape;
|
||||||
|
return true; // 'true' means a new shape has been added to this prim
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback from convex hull creater with a newly created hull.
|
||||||
|
// Just add it to the collection of hulls for this shape.
|
||||||
|
private void HullReturn(ConvexResult result)
|
||||||
|
{
|
||||||
|
m_hulls.Add(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an object in Bullet if it has not already been created
|
||||||
|
// No locking here because this is done when the physics engine is not simulating
|
||||||
|
// Returns 'true' if an object was actually created.
|
||||||
|
private bool CreateObject(bool forceRebuild, BSPrim prim, BulletSim sim, BulletShape shape, ShapeData shapeData)
|
||||||
|
{
|
||||||
|
// the mesh or hull must have already been created in Bullet
|
||||||
|
// m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, LocalID, shape.Type);
|
||||||
|
|
||||||
|
DereferenceBody(prim.BSBody);
|
||||||
|
|
||||||
|
BulletBody aBody;
|
||||||
|
IntPtr bodyPtr = IntPtr.Zero;
|
||||||
|
if (prim.IsSolid)
|
||||||
|
{
|
||||||
|
bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.Ptr, shape.Ptr, shapeData.Position, shapeData.Rotation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.Ptr, shape.Ptr, shapeData.Position, shapeData.Rotation);
|
||||||
|
}
|
||||||
|
aBody = new BulletBody(shapeData.ID, bodyPtr);
|
||||||
|
|
||||||
|
ReferenceBody(aBody);
|
||||||
|
|
||||||
|
prim.BSBody = aBody;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DetailLog(string msg, params Object[] args)
|
||||||
|
{
|
||||||
|
PhysicsScene.PhysicsLogging.Write(msg, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,9 @@ public struct BulletSim
|
||||||
{
|
{
|
||||||
public BulletSim(uint worldId, BSScene bss, IntPtr xx)
|
public BulletSim(uint worldId, BSScene bss, IntPtr xx)
|
||||||
{
|
{
|
||||||
worldID = worldId; scene = bss; Ptr = xx;
|
worldID = worldId;
|
||||||
|
scene = bss;
|
||||||
|
Ptr = xx;
|
||||||
}
|
}
|
||||||
public uint worldID;
|
public uint worldID;
|
||||||
// The scene is only in here so very low level routines have a handle to print debug/error messages
|
// The scene is only in here so very low level routines have a handle to print debug/error messages
|
||||||
|
@ -58,6 +60,16 @@ public struct BulletBody
|
||||||
}
|
}
|
||||||
public IntPtr Ptr;
|
public IntPtr Ptr;
|
||||||
public uint ID;
|
public uint ID;
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
StringBuilder buff = new StringBuilder();
|
||||||
|
buff.Append("<id=");
|
||||||
|
buff.Append(ID.ToString());
|
||||||
|
buff.Append(",p=");
|
||||||
|
buff.Append(Ptr.ToString("X"));
|
||||||
|
buff.Append(">");
|
||||||
|
return buff.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct BulletShape
|
public struct BulletShape
|
||||||
|
@ -66,17 +78,29 @@ public struct BulletShape
|
||||||
{
|
{
|
||||||
Ptr = xx;
|
Ptr = xx;
|
||||||
type=ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
|
type=ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
|
||||||
hashKey = 0;
|
shapeKey = 0;
|
||||||
}
|
}
|
||||||
public BulletShape(IntPtr xx, ShapeData.PhysicsShapeType typ)
|
public BulletShape(IntPtr xx, ShapeData.PhysicsShapeType typ)
|
||||||
{
|
{
|
||||||
Ptr = xx;
|
Ptr = xx;
|
||||||
type = typ;
|
type = typ;
|
||||||
hashKey = 0;
|
shapeKey = 0;
|
||||||
}
|
}
|
||||||
public IntPtr Ptr;
|
public IntPtr Ptr;
|
||||||
public ShapeData.PhysicsShapeType type;
|
public ShapeData.PhysicsShapeType type;
|
||||||
public ulong hashKey;
|
public ulong shapeKey;
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
StringBuilder buff = new StringBuilder();
|
||||||
|
buff.Append("<p=");
|
||||||
|
buff.Append(Ptr.ToString("X"));
|
||||||
|
buff.Append(",s=");
|
||||||
|
buff.Append(type.ToString());
|
||||||
|
buff.Append(",k=");
|
||||||
|
buff.Append(shapeKey.ToString("X"));
|
||||||
|
buff.Append(">");
|
||||||
|
return buff.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// An allocated Bullet btConstraint
|
// An allocated Bullet btConstraint
|
||||||
|
@ -155,10 +179,21 @@ public struct ShapeData
|
||||||
public float Restitution;
|
public float Restitution;
|
||||||
public float Collidable; // true of things bump into this
|
public float Collidable; // true of things bump into this
|
||||||
public float Static; // true if a static object. Otherwise gravity, etc.
|
public float Static; // true if a static object. Otherwise gravity, etc.
|
||||||
|
public float Solid; // true if object cannot be passed through
|
||||||
|
public Vector3 Size;
|
||||||
|
|
||||||
// note that bools are passed as floats since bool size changes by language and architecture
|
// note that bools are passed as floats since bool size changes by language and architecture
|
||||||
public const float numericTrue = 1f;
|
public const float numericTrue = 1f;
|
||||||
public const float numericFalse = 0f;
|
public const float numericFalse = 0f;
|
||||||
|
|
||||||
|
// The native shapes have predefined shape hash keys
|
||||||
|
public enum FixedShapeKey : ulong
|
||||||
|
{
|
||||||
|
KEY_BOX = 1,
|
||||||
|
KEY_SPHERE = 2,
|
||||||
|
KEY_CONE = 3,
|
||||||
|
KEY_CYLINDER = 4,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct SweepHit
|
public struct SweepHit
|
||||||
|
|
Loading…
Reference in New Issue