From 75a05c16c5c0ec0712f7f564b60530e0a3fd1c82 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 31 Jan 2013 15:52:50 -0800 Subject: [PATCH] BulletSim: fix crash caused when linksets were rebuilt. A problem added when individual child pos/rot changes were implementated a week or so ago. Remove some passing of inTaintTime flag when it was never false. --- .../Physics/BulletSPlugin/BSCharacter.cs | 4 +- .../BulletSPlugin/BSLinksetCompound.cs | 48 +++++--- .../Region/Physics/BulletSPlugin/BSPrim.cs | 16 ++- .../BulletSPlugin/BSShapeCollection.cs | 114 +++++++++--------- .../Physics/BulletSPlugin/BulletSimTODO.txt | 4 + 5 files changed, 106 insertions(+), 80 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 73354bbce9..192bcb5f3a 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -126,9 +126,9 @@ public sealed class BSCharacter : BSPhysObject DetailLog("{0},BSCharacter.Destroy", LocalID); PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() { - PhysicsScene.Shapes.DereferenceBody(PhysBody, true /* inTaintTime */, null /* bodyCallback */); + PhysicsScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); PhysBody.Clear(); - PhysicsScene.Shapes.DereferenceShape(PhysShape, true /* inTaintTime */, null /* bodyCallback */); + PhysicsScene.Shapes.DereferenceShape(PhysShape, null /* bodyCallback */); PhysShape.Clear(); }); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 92f6ee298c..6c6ca09d3f 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -219,28 +219,45 @@ public sealed class BSLinksetCompound : BSLinkset { // Gather the child info. It might not be there if the linkset is in transition. BSLinksetCompoundInfo lsi = updated.LinksetInfo as BSLinksetCompoundInfo; + + // The linksetInfo will need to be rebuilt either here or when the linkset is rebuilt if (LinksetRoot.PhysShape.HasPhysicalShape && lsi != null) { if (PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape)) { - BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, lsi.Index); - if (linksetChildShape.HasPhysicalShape) + int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape); + if (lsi.Index < numLinksetChildren) { - // Compute the offset from the center-of-gravity - BSLinksetCompoundInfo newLsi = new BSLinksetCompoundInfo(lsi.Index, LinksetRoot, updated, LinksetRoot.PositionDisplacement); - PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, lsi.Index, - newLsi.OffsetFromCenterOfMass, - newLsi.OffsetRot, - true /* shouldRecalculateLocalAabb */); - DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},newLsi={2}", - updated.LocalID, whichUpdated, newLsi); - updated.LinksetInfo = newLsi; - updatedChild = true; + // It is possible that the linkset is still under construction and the child is not yet + // inserted into the compound shape. A rebuild of the linkset in a pre-step action will + // build the whole thing with the new position or rotation. + // This must be checked for because Bullet references the child array but does no validity + // checking of the child index passed. + BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, lsi.Index); + if (linksetChildShape.HasPhysicalShape) + { + // Compute the offset from the center-of-gravity + BSLinksetCompoundInfo newLsi = new BSLinksetCompoundInfo(lsi.Index, LinksetRoot, updated, LinksetRoot.PositionDisplacement); + PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, lsi.Index, + newLsi.OffsetFromCenterOfMass, + newLsi.OffsetRot, + true /* shouldRecalculateLocalAabb */); + updated.LinksetInfo = newLsi; + updatedChild = true; + DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},newLsi={2}", + updated.LocalID, whichUpdated, newLsi); + } + else // DEBUG DEBUG + { // DEBUG DEBUG + DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}", + updated.LocalID, linksetChildShape); + } // DEBUG DEBUG } else // DEBUG DEBUG { // DEBUG DEBUG - DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}", - updated.LocalID, linksetChildShape); + // the child is not yet in the compound shape. This is non-fatal. + DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}", + updated.LocalID, numLinksetChildren, lsi.Index); } // DEBUG DEBUG } else // DEBUG DEBUG @@ -256,6 +273,9 @@ public sealed class BSLinksetCompound : BSLinkset if (!updatedChild) { // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info. + // Note that there are several ways through this code that will not update the child that can + // occur if the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since + // there will already be a rebuild scheduled. DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", updated.LocalID, whichUpdated); updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 0b81122da4..54bf063add 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -146,9 +146,9 @@ public sealed class BSPrim : BSPhysObject { DetailLog("{0},BSPrim.Destroy,taint,", LocalID); // If there are physical body and shape, release my use of same. - PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); + PhysicsScene.Shapes.DereferenceBody(PhysBody, null); PhysBody.Clear(); - PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); + PhysicsScene.Shapes.DereferenceShape(PhysShape, null); PhysShape.Clear(); }); } @@ -181,11 +181,19 @@ public sealed class BSPrim : BSPhysObject public override bool ForceBodyShapeRebuild(bool inTaintTime) { - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() + if (inTaintTime) { _mass = CalculateMass(); // changing the shape changes the mass CreateGeomAndObject(true); - }); + } + else + { + PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", delegate() + { + _mass = CalculateMass(); // changing the shape changes the mass + CreateGeomAndObject(true); + }); + } return true; } public override bool Grabbed { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index e2daa72318..9febd90d2b 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs @@ -133,48 +133,44 @@ public sealed class BSShapeCollection : IDisposable // Track another user of a body. // We presume the caller has allocated the body. // Bodies only have one user so the body is just put into the world if not already there. - public void ReferenceBody(BulletBody body, bool inTaintTime) + private void ReferenceBody(BulletBody body) { lock (m_collectionActivityLock) { if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); - PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() + if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) { - if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) - { - PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body); - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); - } - }); + PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body); + if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); + } } } // Release the usage of a body. // Called when releasing use of a BSBody. BSShape is handled separately. - public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) + // Called in taint time. + public void DereferenceBody(BulletBody body, BodyDestructionCallback bodyCallback ) { if (!body.HasPhysicalBody) return; + PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody"); + lock (m_collectionActivityLock) { - PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() + if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body); + // If the caller needs to know the old body is going away, pass the event up. + if (bodyCallback != null) bodyCallback(body); + + if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) { - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", - body.ID, body, inTaintTime); - // If the caller needs to know the old body is going away, pass the event up. - if (bodyCallback != null) bodyCallback(body); + PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body); + if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); + } - if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) - { - PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body); - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); - } - - // Zero any reference to the shape so it is not freed when the body is deleted. - PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null); - PhysicsScene.PE.DestroyObject(PhysicsScene.World, body); - }); + // Zero any reference to the shape so it is not freed when the body is deleted. + PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null); + PhysicsScene.PE.DestroyObject(PhysicsScene.World, body); } } @@ -245,44 +241,43 @@ public sealed class BSShapeCollection : IDisposable } // Release the usage of a shape. - public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) + public void DereferenceShape(BulletShape shape, ShapeDestructionCallback shapeCallback) { if (!shape.HasPhysicalShape) return; - PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() + PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceShape"); + + if (shape.HasPhysicalShape) { - if (shape.HasPhysicalShape) + if (shape.isNativeShape) { - if (shape.isNativeShape) + // Native shapes are not tracked and are released immediately + if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1}", + BSScene.DetailLogZero, shape.AddrString); + if (shapeCallback != null) shapeCallback(shape); + PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape); + } + else + { + switch (shape.type) { - // Native shapes are not tracked and are released immediately - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", - BSScene.DetailLogZero, shape.AddrString, inTaintTime); - if (shapeCallback != null) shapeCallback(shape); - PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape); - } - else - { - switch (shape.type) - { - case BSPhysicsShapeType.SHAPE_HULL: - DereferenceHull(shape, shapeCallback); - break; - case BSPhysicsShapeType.SHAPE_MESH: - DereferenceMesh(shape, shapeCallback); - break; - case BSPhysicsShapeType.SHAPE_COMPOUND: - DereferenceCompound(shape, shapeCallback); - break; - case BSPhysicsShapeType.SHAPE_UNKNOWN: - break; - default: - break; - } + case BSPhysicsShapeType.SHAPE_HULL: + DereferenceHull(shape, shapeCallback); + break; + case BSPhysicsShapeType.SHAPE_MESH: + DereferenceMesh(shape, shapeCallback); + break; + case BSPhysicsShapeType.SHAPE_COMPOUND: + DereferenceCompound(shape, shapeCallback); + break; + case BSPhysicsShapeType.SHAPE_UNKNOWN: + break; + default: + break; } } - }); + } } // Count down the reference count for a mesh shape @@ -393,7 +388,7 @@ public sealed class BSShapeCollection : IDisposable if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) { - DereferenceShape(shapeInfo, true, null); + DereferenceShape(shapeInfo, null); } else { @@ -543,7 +538,7 @@ public sealed class BSShapeCollection : IDisposable ShapeDestructionCallback shapeCallback) { // release any previous shape - DereferenceShape(prim.PhysShape, true, shapeCallback); + DereferenceShape(prim.PhysShape, shapeCallback); BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); @@ -611,7 +606,7 @@ public sealed class BSShapeCollection : IDisposable prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); // Since we're recreating new, get rid of the reference to the previous shape - DereferenceShape(prim.PhysShape, true, shapeCallback); + DereferenceShape(prim.PhysShape, shapeCallback); newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod); // Take evasive action if the mesh was not constructed. @@ -682,7 +677,7 @@ public sealed class BSShapeCollection : IDisposable prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); // Remove usage of the previous shape. - DereferenceShape(prim.PhysShape, true, shapeCallback); + DereferenceShape(prim.PhysShape, shapeCallback); newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); newShape = VerifyMeshCreated(newShape, prim); @@ -817,7 +812,6 @@ public sealed class BSShapeCollection : IDisposable // Don't need to do this as the shape is freed when the new root shape is created below. // DereferenceShape(prim.PhysShape, true, shapeCallback); - BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false); // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. @@ -956,7 +950,7 @@ public sealed class BSShapeCollection : IDisposable if (mustRebuild || forceRebuild) { // Free any old body - DereferenceBody(prim.PhysBody, true, bodyCallback); + DereferenceBody(prim.PhysBody, bodyCallback); BulletBody aBody; if (prim.IsSolid) @@ -970,7 +964,7 @@ public sealed class BSShapeCollection : IDisposable if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); } - ReferenceBody(aBody, true); + ReferenceBody(aBody); prim.PhysBody = aBody; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index d574a492cb..7dfdec1db9 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt @@ -65,6 +65,10 @@ Vehicle attributes are not restored when a vehicle is rezzed on region creation GENERAL TODO LIST: ================================================= +Collisions are inconsistant: arrows are supposed to hit and report collision. Often don't. + If arrow show at prim, collision reported about 1/3 of time. If collision reported, + both arrow and prim report it. The arrow bounces off the prim 9 out of 10 times. + Shooting 5m sphere "arrows" at 60m/s. llMoveToTarget objects are not effected by gravity until target is removed. Compute CCD parameters based on body size Can solver iterations be changed per body/shape? Can be for constraints but what