BulletSim: Move construction of compound linkset from ShapeCollection
into LinksetCompound where it should be. Create meshes for native shapes when part of a compound linkset because scale is currently per object and not per collision shape. Don't schedule a LinksetCompound refresh if just changing properties.integration
parent
1dc23b2b97
commit
498ea76e63
|
@ -34,7 +34,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
public sealed class BSLinksetCompound : BSLinkset
|
public sealed class BSLinksetCompound : BSLinkset
|
||||||
{
|
{
|
||||||
// private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
|
private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
|
||||||
|
|
||||||
public BSLinksetCompound(BSScene scene, BSPhysObject parent)
|
public BSLinksetCompound(BSScene scene, BSPhysObject parent)
|
||||||
{
|
{
|
||||||
|
@ -58,6 +58,12 @@ public sealed class BSLinksetCompound : BSLinkset
|
||||||
// This is queued in the 'post taint' queue so the
|
// This is queued in the 'post taint' queue so the
|
||||||
// refresh will happen once after all the other taints are applied.
|
// refresh will happen once after all the other taints are applied.
|
||||||
public override void Refresh(BSPhysObject requestor)
|
public override void Refresh(BSPhysObject requestor)
|
||||||
|
{
|
||||||
|
// External request for Refresh (from BSPrim) is not necessary
|
||||||
|
// InternalRefresh(requestor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InternalRefresh(BSPhysObject requestor)
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID);
|
DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID);
|
||||||
// Queue to happen after all the other taint processing
|
// Queue to happen after all the other taint processing
|
||||||
|
@ -135,13 +141,13 @@ public sealed class BSLinksetCompound : BSLinkset
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2},isRoot={3}",
|
DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
|
||||||
child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child));
|
child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child));
|
||||||
|
|
||||||
if (!IsRoot(child))
|
if (!IsRoot(child))
|
||||||
{
|
{
|
||||||
// Cause the current shape to be freed and the new one to be built.
|
// Cause the current shape to be freed and the new one to be built.
|
||||||
Refresh(LinksetRoot);
|
InternalRefresh(LinksetRoot);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +175,7 @@ public sealed class BSLinksetCompound : BSLinkset
|
||||||
DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
|
DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
|
||||||
|
|
||||||
// Cause constraints and assorted properties to be recomputed before the next simulation step.
|
// Cause constraints and assorted properties to be recomputed before the next simulation step.
|
||||||
Refresh(LinksetRoot);
|
InternalRefresh(LinksetRoot);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -196,34 +202,68 @@ public sealed class BSLinksetCompound : BSLinkset
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Schedule a rebuild of the linkset before the next simulation tick.
|
// Schedule a rebuild of the linkset before the next simulation tick.
|
||||||
Refresh(LinksetRoot);
|
InternalRefresh(LinksetRoot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called before the simulation step to make sure the compound based linkset
|
||||||
// Call each of the constraints that make up this linkset and recompute the
|
|
||||||
// various transforms and variables. Create constraints of not created yet.
|
|
||||||
// Called before the simulation step to make sure the constraint based linkset
|
|
||||||
// is all initialized.
|
// is all initialized.
|
||||||
|
// Constraint linksets are rebuilt every time.
|
||||||
|
// Note that this works for rebuilding just the root after a linkset is taken apart.
|
||||||
// Called at taint time!!
|
// Called at taint time!!
|
||||||
private void RecomputeLinksetCompound()
|
private void RecomputeLinksetCompound()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},numChildren={2}",
|
// Cause the root shape to be rebuilt as a compound object with just the root in it
|
||||||
LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), NumberOfChildren);
|
|
||||||
|
|
||||||
LinksetRoot.ForceBodyShapeRebuild(true);
|
LinksetRoot.ForceBodyShapeRebuild(true);
|
||||||
|
|
||||||
|
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
|
||||||
|
LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
|
||||||
|
|
||||||
|
ForEachMember(delegate(BSPhysObject cPrim)
|
||||||
|
{
|
||||||
|
if (!IsRoot(cPrim))
|
||||||
|
{
|
||||||
|
OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
|
||||||
|
OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
|
||||||
|
OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
|
||||||
|
|
||||||
|
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
|
||||||
|
LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot);
|
||||||
|
|
||||||
|
if (cPrim.PhysShape.isNativeShape)
|
||||||
|
{
|
||||||
|
// Native shapes are not shared so we need to create a new one.
|
||||||
|
// A mesh or hull is created because scale is not available on a native shape.
|
||||||
|
// (TODO: Bullet does have a btScaledCollisionShape. Can that be used?)
|
||||||
|
BulletShape saveShape = cPrim.PhysShape;
|
||||||
|
PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
|
||||||
|
BulletShape newShape = cPrim.PhysShape;
|
||||||
|
cPrim.PhysShape = saveShape;
|
||||||
|
BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// For the shared shapes (meshes and hulls) just use the shape in the child
|
||||||
|
if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
|
||||||
|
{
|
||||||
|
PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
|
||||||
|
LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
|
||||||
|
}
|
||||||
|
BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
float linksetMass = LinksetMass;
|
float linksetMass = LinksetMass;
|
||||||
LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
|
LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
|
||||||
|
|
||||||
// DEBUG: see of inter-linkset collisions are causing problems
|
// DEBUG: see of inter-linkset collisions are causing problems
|
||||||
// BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
|
// BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
|
||||||
// (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
|
// (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
|
||||||
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,end,rBody={1},linksetMass={2}",
|
|
||||||
LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), linksetMass);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,6 +116,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
// True if initialized and ready to do simulation steps
|
// True if initialized and ready to do simulation steps
|
||||||
private bool m_initialized = false;
|
private bool m_initialized = false;
|
||||||
|
|
||||||
|
// Flag which is true when processing taints.
|
||||||
|
// Not guaranteed to be correct all the time (don't depend on this) but good for debugging.
|
||||||
|
public bool InTaintTime { get; private set; }
|
||||||
|
|
||||||
// Pinned memory used to pass step information between managed and unmanaged
|
// Pinned memory used to pass step information between managed and unmanaged
|
||||||
private int m_maxCollisionsPerFrame;
|
private int m_maxCollisionsPerFrame;
|
||||||
private CollisionDesc[] m_collisionArray;
|
private CollisionDesc[] m_collisionArray;
|
||||||
|
@ -270,6 +274,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
TerrainManager = new BSTerrainManager(this);
|
TerrainManager = new BSTerrainManager(this);
|
||||||
TerrainManager.CreateInitialGroundPlaneAndTerrain();
|
TerrainManager.CreateInitialGroundPlaneAndTerrain();
|
||||||
|
|
||||||
|
m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation);
|
||||||
|
|
||||||
|
InTaintTime = false;
|
||||||
m_initialized = true;
|
m_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,8 +714,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
// here just before the physics engine is called to step the simulation.
|
// here just before the physics engine is called to step the simulation.
|
||||||
public void ProcessTaints()
|
public void ProcessTaints()
|
||||||
{
|
{
|
||||||
|
InTaintTime = true;
|
||||||
ProcessRegularTaints();
|
ProcessRegularTaints();
|
||||||
ProcessPostTaintTaints();
|
ProcessPostTaintTaints();
|
||||||
|
InTaintTime = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessRegularTaints()
|
private void ProcessRegularTaints()
|
||||||
|
@ -851,6 +860,17 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool AssertInTaintTime(string whereFrom)
|
||||||
|
{
|
||||||
|
if (!InTaintTime)
|
||||||
|
{
|
||||||
|
DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
|
||||||
|
m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
|
||||||
|
Util.PrintCallStack();
|
||||||
|
}
|
||||||
|
return InTaintTime;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion // Taints
|
#endregion // Taints
|
||||||
|
|
||||||
#region Vehicles
|
#region Vehicles
|
||||||
|
@ -1214,8 +1234,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
(s) => { return s.m_params[0].numberOfSolverIterations; },
|
(s) => { return s.m_params[0].numberOfSolverIterations; },
|
||||||
(s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
|
(s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
|
||||||
|
|
||||||
new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound)",
|
new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
|
||||||
(float)BSLinkset.LinksetImplementation.Constraint,
|
(float)BSLinkset.LinksetImplementation.Compound,
|
||||||
(s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); },
|
(s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); },
|
||||||
(s) => { return s.m_params[0].linksetImplementation; },
|
(s) => { return s.m_params[0].linksetImplementation; },
|
||||||
(s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ),
|
(s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ),
|
||||||
|
|
|
@ -92,6 +92,8 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
|
public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
|
||||||
ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
|
ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
|
||||||
{
|
{
|
||||||
|
PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
|
||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
// This lock could probably be pushed down lower but building shouldn't take long
|
// This lock could probably be pushed down lower but building shouldn't take long
|
||||||
|
@ -121,7 +123,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
{
|
{
|
||||||
lock (m_collectionActivityLock)
|
lock (m_collectionActivityLock)
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body);
|
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
|
||||||
PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
|
PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
|
||||||
{
|
{
|
||||||
if (!BulletSimAPI.IsInWorld2(body.ptr))
|
if (!BulletSimAPI.IsInWorld2(body.ptr))
|
||||||
|
@ -165,7 +167,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
// Meshes and hulls for the same shape have the same hash key.
|
// Meshes and hulls for the same shape have the same hash key.
|
||||||
// NOTE that native shapes are not added to the mesh list or removed.
|
// NOTE that native shapes are not added to the mesh list or removed.
|
||||||
// Returns 'true' if this is the initial reference to the shape. Otherwise reused.
|
// Returns 'true' if this is the initial reference to the shape. Otherwise reused.
|
||||||
private bool ReferenceShape(BulletShape shape)
|
public bool ReferenceShape(BulletShape shape)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
switch (shape.type)
|
switch (shape.type)
|
||||||
|
@ -276,8 +278,8 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
if (shapeCallback != null) shapeCallback(shape);
|
if (shapeCallback != null) shapeCallback(shape);
|
||||||
meshDesc.lastReferenced = System.DateTime.Now;
|
meshDesc.lastReferenced = System.DateTime.Now;
|
||||||
Meshes[shape.shapeKey] = meshDesc;
|
Meshes[shape.shapeKey] = meshDesc;
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceMesh,key={1},refCnt={2}",
|
DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
|
||||||
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
|
BSScene.DetailLogZero, shape, meshDesc.referenceCount);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,8 +299,8 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
|
|
||||||
hullDesc.lastReferenced = System.DateTime.Now;
|
hullDesc.lastReferenced = System.DateTime.Now;
|
||||||
Hulls[shape.shapeKey] = hullDesc;
|
Hulls[shape.shapeKey] = hullDesc;
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceHull,key={1},refCnt={2}",
|
DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
|
||||||
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
|
BSScene.DetailLogZero, shape, hullDesc.referenceCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,8 +321,11 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X"));
|
BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr);
|
int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr);
|
||||||
for (int ii = 0; ii < numChildren; ii++)
|
DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
|
||||||
|
|
||||||
|
for (int ii = numChildren - 1; ii >= 0; ii--)
|
||||||
{
|
{
|
||||||
IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii);
|
IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii);
|
||||||
DereferenceAnonCollisionShape(childShape);
|
DereferenceAnonCollisionShape(childShape);
|
||||||
|
@ -343,6 +348,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
shapeInfo.isNativeShape = true;
|
shapeInfo.isNativeShape = true;
|
||||||
shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
|
shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
|
||||||
}
|
}
|
||||||
|
DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
|
||||||
|
|
||||||
DereferenceShape(shapeInfo, true, null);
|
DereferenceShape(shapeInfo, true, null);
|
||||||
}
|
}
|
||||||
|
@ -440,23 +446,32 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a simple shape is not happening, create a mesh and possibly a hull.
|
// If a simple shape is not happening, create a mesh and possibly a hull.
|
||||||
// Note that if it's a native shape, the check for physical/non-physical is not
|
|
||||||
// made. Native shapes work in either case.
|
|
||||||
if (!haveShape && pbs != null)
|
if (!haveShape && pbs != null)
|
||||||
{
|
{
|
||||||
if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
|
ret = CreateGeomMeshOrHull(prim, shapeCallback);
|
||||||
{
|
}
|
||||||
// Update prim.BSShape to reference a hull of this shape.
|
|
||||||
ret = GetReferenceToHull(prim,shapeCallback);
|
return ret;
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
|
}
|
||||||
prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
|
|
||||||
}
|
public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
|
||||||
else
|
{
|
||||||
{
|
|
||||||
ret = GetReferenceToMesh(prim, shapeCallback);
|
bool ret = false;
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
|
// Note that if it's a native shape, the check for physical/non-physical is not
|
||||||
prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
|
// made. Native shapes work in either case.
|
||||||
}
|
if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
|
||||||
|
{
|
||||||
|
// Update prim.BSShape to reference a hull of this shape.
|
||||||
|
ret = GetReferenceToHull(prim,shapeCallback);
|
||||||
|
DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
|
||||||
|
prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = GetReferenceToMesh(prim, shapeCallback);
|
||||||
|
DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
|
||||||
|
prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -743,32 +758,16 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
// This shouldn't be to bad since most of the parts will be meshes that had been built previously.
|
// This shouldn't be to bad since most of the parts will be meshes that had been built previously.
|
||||||
private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
|
private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
|
||||||
{
|
{
|
||||||
|
// Remove reference to the old shape
|
||||||
|
// Don't need to do this as the shape is freed when we create the new root shape below.
|
||||||
|
// DereferenceShape(prim.PhysShape, true, shapeCallback);
|
||||||
|
|
||||||
BulletShape cShape = new BulletShape(
|
BulletShape cShape = new BulletShape(
|
||||||
BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr), ShapeData.PhysicsShapeType.SHAPE_COMPOUND);
|
BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr), ShapeData.PhysicsShapeType.SHAPE_COMPOUND);
|
||||||
|
|
||||||
// The prim's linkset is the source of the children.
|
// Create the shape for the root prim and add it to the compound shape
|
||||||
// TODO: there is too much knowledge here about the internals of linksets and too much
|
|
||||||
// dependency on the relationship of compound shapes and linksets (what if we want to use
|
|
||||||
// compound shapes for something else?). Think through this and clean up so the
|
|
||||||
// appropriate knowledge is used at the correct software levels.
|
|
||||||
|
|
||||||
// Recreate the geometry of the root prim (might have been a linkset root in the past)
|
|
||||||
CreateGeomNonSpecial(true, prim, null);
|
CreateGeomNonSpecial(true, prim, null);
|
||||||
|
BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity);
|
||||||
BSPhysObject rootPrim = prim.Linkset.LinksetRoot;
|
|
||||||
|
|
||||||
prim.Linkset.ForEachMember(delegate(BSPhysObject cPrim)
|
|
||||||
{
|
|
||||||
OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(rootPrim.RawOrientation);
|
|
||||||
OMV.Vector3 displacementPos = (cPrim.RawPosition - rootPrim.RawPosition) * invRootOrientation;
|
|
||||||
OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
|
|
||||||
|
|
||||||
DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
|
|
||||||
prim.LocalID, cPrim.LocalID, cPrim.PhysShape.ptr.ToString("X"), displacementPos, displacementRot);
|
|
||||||
|
|
||||||
BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
prim.PhysShape = cShape;
|
prim.PhysShape = cShape;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue