From c22a2ab7d21803050317527476c2e18aa2edb40f Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 24 Apr 2013 08:05:42 -0700 Subject: [PATCH] BulletSim: partial addition of BSShape class code preparing for different physical mesh representations (simplified convex meshes) and avatar mesh. --- .../BulletSPlugin/BSShapeCollection.cs | 28 +-- .../Region/Physics/BulletSPlugin/BSShapes.cs | 223 ++++++++++++++---- 2 files changed, 195 insertions(+), 56 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 1976c42ef3..bc264602ef 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs @@ -612,7 +612,7 @@ public sealed class BSShapeCollection : IDisposable newShape = CreatePhysicalMesh(prim, newMeshKey, prim.BaseShape, prim.Size, lod); // Take evasive action if the mesh was not constructed. - newShape = VerifyMeshCreated(newShape, prim); + newShape = VerifyMeshCreated(PhysicsScene, newShape, prim); ReferenceShape(newShape); @@ -719,7 +719,7 @@ public sealed class BSShapeCollection : IDisposable newShape = CreatePhysicalHull(prim, newHullKey, prim.BaseShape, prim.Size, lod); // It might not have been created if we're waiting for an asset. - newShape = VerifyMeshCreated(newShape, prim); + newShape = VerifyMeshCreated(PhysicsScene, newShape, prim); ReferenceShape(newShape); @@ -923,7 +923,7 @@ public sealed class BSShapeCollection : IDisposable // Create a hash of all the shape parameters to be used as a key // for this particular shape. - private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) + public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) { // level of detail based on size and type of the object float lod = BSParam.MeshLOD; @@ -944,7 +944,7 @@ public sealed class BSShapeCollection : IDisposable return pbs.GetMeshKey(size, lod); } // For those who don't want the LOD - private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs) + public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs) { float lod; return ComputeShapeKey(size, pbs, out lod); @@ -957,7 +957,7 @@ public sealed class BSShapeCollection : IDisposable // us to not loop forever. // Called after creating a physical mesh or hull. If the physical shape was created, // just return. - private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) + public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim) { // If the shape was successfully created, nothing more to do if (newShape.HasPhysicalShape) @@ -969,7 +969,7 @@ public sealed class BSShapeCollection : IDisposable if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) { prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; - PhysicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}", + physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}", LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); } else @@ -981,14 +981,14 @@ public sealed class BSShapeCollection : IDisposable && prim.BaseShape.SculptTexture != OMV.UUID.Zero ) { - DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID); + physicsScene.DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID); // Multiple requestors will know we're waiting for this asset prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting; BSPhysObject xprim = prim; Util.FireAndForget(delegate { - RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; + RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod; if (assetProvider != null) { BSPhysObject yprim = xprim; // probably not necessary, but, just in case. @@ -1016,7 +1016,7 @@ public sealed class BSShapeCollection : IDisposable yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched; else yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; - DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}", + physicsScene.DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}", yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); }); @@ -1024,8 +1024,8 @@ public sealed class BSShapeCollection : IDisposable else { xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; - PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", - LogHeader, PhysicsScene.Name); + physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", + LogHeader, physicsScene.Name); } }); } @@ -1033,15 +1033,15 @@ public sealed class BSShapeCollection : IDisposable { if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) { - PhysicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}", + physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}", LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); } } } // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. - BulletShape fillinShape = BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); - DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID); + BulletShape fillinShape = physicsScene.Shapes.BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + physicsScene.DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID); return fillinShape; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index ee18379a2e..dd5ae1ae60 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -29,6 +29,9 @@ using System; using System.Collections.Generic; using System.Text; +using OpenSim.Framework; +using OpenSim.Region.Physics.Manager; + using OMV = OpenMetaverse; namespace OpenSim.Region.Physics.BulletSPlugin @@ -37,11 +40,19 @@ public abstract class BSShape { public int referenceCount { get; set; } public DateTime lastReferenced { get; set; } + public BulletShape physShapeInfo { get; set; } public BSShape() { referenceCount = 0; lastReferenced = DateTime.Now; + physShapeInfo = new BulletShape(); + } + public BSShape(BulletShape pShape) + { + referenceCount = 0; + lastReferenced = DateTime.Now; + physShapeInfo = pShape; } // Get a reference to a physical shape. Create if it doesn't exist @@ -79,21 +90,30 @@ public abstract class BSShape return ret; } - public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + private static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) { + BSShapeMesh.GetReference(physicsScene, forceRebuild, prim); + BSShapeHull.GetReference(physicsScene, forceRebuild, prim); return null; } - public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + + // Called when this shape is being used again. + public virtual void IncrementReference() { - return null; + referenceCount++; + lastReferenced = DateTime.Now; + } + + // Called when this shape is being used again. + public virtual void DecrementReference() + { + referenceCount--; + lastReferenced = DateTime.Now; } // Release the use of a physical shape. public abstract void Dereference(BSScene physicsScene); - // All shapes have a static call to get a reference to the physical shape - // protected abstract static BSShape GetReference(); - // Returns a string for debugging that uniquily identifies the memory used by this instance public virtual string AddrString { @@ -112,6 +132,7 @@ public abstract class BSShape } } +// ============================================================================================================ public class BSShapeNull : BSShape { public BSShapeNull() : base() @@ -121,23 +142,39 @@ public class BSShapeNull : BSShape public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } } +// ============================================================================================================ public class BSShapeNative : BSShape { private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; - public BSShapeNative() : base() + public BSShapeNative(BulletShape pShape) : base(pShape) { } - public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, - BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) - { - // Native shapes are not shared and are always built anew. - //return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); - return null; - } - private BSShapeNative(BSScene physicsScene, BSPhysObject prim, - BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) + public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, + BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) { + // Native shapes are not shared and are always built anew. + return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey)); + } + + // Make this reference to the physical shape go away since native shapes are not shared. + public override void Dereference(BSScene physicsScene) + { + // Native shapes are not tracked and are released immediately + if (physShapeInfo.HasPhysicalShape) + { + physicsScene.DetailLog("{0},BSShapeNative.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); + physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); + } + physShapeInfo.Clear(); + // Garbage collection will free up this instance. + } + + private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim, + BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) + { + BulletShape newShape; + ShapeData nativeShapeData = new ShapeData(); nativeShapeData.Type = shapeType; nativeShapeData.ID = prim.LocalID; @@ -146,63 +183,164 @@ public class BSShapeNative : BSShape nativeShapeData.MeshKey = (ulong)shapeKey; nativeShapeData.HullKey = (ulong)shapeKey; - - /* if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) { - ptr = PhysicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); - physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); + newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); + physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale); } else { - ptr = PhysicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); + newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); } - if (ptr == IntPtr.Zero) + if (!newShape.HasPhysicalShape) { physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", LogHeader, prim.LocalID, shapeType); } - type = shapeType; - key = (UInt64)shapeKey; - */ - } - // Make this reference to the physical shape go away since native shapes are not shared. - public override void Dereference(BSScene physicsScene) - { - /* - // Native shapes are not tracked and are released immediately - physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); - PhysicsScene.PE.DeleteCollisionShape(physicsScene.World, this); - ptr = IntPtr.Zero; - // Garbage collection will free up this instance. - */ + newShape.type = shapeType; + newShape.isNativeShape = true; + newShape.shapeKey = (UInt64)shapeKey; + return newShape; } + } +// ============================================================================================================ public class BSShapeMesh : BSShape { private static string LogHeader = "[BULLETSIM SHAPE MESH]"; private static Dictionary Meshes = new Dictionary(); - public BSShapeMesh() : base() + public BSShapeMesh(BulletShape pShape) : base(pShape) { } - public static BSShape GetReference() { return new BSShapeNull(); } - public override void Dereference(BSScene physicsScene) { } + public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + { + float lod; + System.UInt64 newMeshKey = BSShapeCollection.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); + + physicsScene.DetailLog("{0},BSShapeMesh,create,oldKey={1},newKey={2},size={3},lod={4}", + prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod); + + BSShapeMesh retMesh; + lock (Meshes) + { + if (Meshes.TryGetValue(newMeshKey, out retMesh)) + { + // The mesh has already been created. Return a new reference to same. + retMesh.IncrementReference(); + } + else + { + // An instance of this mesh has not been created. Build and remember same. + BulletShape newShape = CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); + // Take evasive action if the mesh was not constructed. + newShape = BSShapeCollection.VerifyMeshCreated(physicsScene, newShape, prim); + + retMesh = new BSShapeMesh(newShape); + + Meshes.Add(newMeshKey, retMesh); + } + } + return retMesh; + } + public override void Dereference(BSScene physicsScene) + { + lock (Meshes) + { + this.DecrementReference(); + // TODO: schedule aging and destruction of unused meshes. + } + } + + private static BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, + PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) + { + BulletShape newShape = null; + + IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, + false, // say it is not physical so a bounding box is not built + false // do not cache the mesh and do not use previously built versions + ); + + if (meshData != null) + { + + int[] indices = meshData.getIndexListAsInt(); + int realIndicesIndex = indices.Length; + float[] verticesAsFloats = meshData.getVertexListAsFloat(); + + if (BSParam.ShouldRemoveZeroWidthTriangles) + { + // Remove degenerate triangles. These are triangles with two of the vertices + // are the same. This is complicated by the problem that vertices are not + // made unique in sculpties so we have to compare the values in the vertex. + realIndicesIndex = 0; + for (int tri = 0; tri < indices.Length; tri += 3) + { + // Compute displacements into vertex array for each vertex of the triangle + int v1 = indices[tri + 0] * 3; + int v2 = indices[tri + 1] * 3; + int v3 = indices[tri + 2] * 3; + // Check to see if any two of the vertices are the same + if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0] + && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1] + && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2]) + || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0] + && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1] + && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2]) + || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0] + && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1] + && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) ) + ) + { + // None of the vertices of the triangles are the same. This is a good triangle; + indices[realIndicesIndex + 0] = indices[tri + 0]; + indices[realIndicesIndex + 1] = indices[tri + 1]; + indices[realIndicesIndex + 2] = indices[tri + 2]; + realIndicesIndex += 3; + } + } + } + physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}", + BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); + + if (realIndicesIndex != 0) + { + newShape = physicsScene.PE.CreateMeshShape(physicsScene.World, + realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats); + } + else + { + physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}", + LogHeader, prim.PhysObjectName, prim.RawPosition, physicsScene.Name); + } + } + newShape.shapeKey = newMeshKey; + + return newShape; + } } +// ============================================================================================================ public class BSShapeHull : BSShape { private static string LogHeader = "[BULLETSIM SHAPE HULL]"; private static Dictionary Hulls = new Dictionary(); - public BSShapeHull() : base() + public BSShapeHull(BulletShape pShape) : base(pShape) + { + } + public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + { + return new BSShapeNull(); + } + public override void Dereference(BSScene physicsScene) { } - public static BSShape GetReference() { return new BSShapeNull(); } - public override void Dereference(BSScene physicsScene) { } } +// ============================================================================================================ public class BSShapeCompound : BSShape { private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; @@ -216,6 +354,7 @@ public class BSShapeCompound : BSShape public override void Dereference(BSScene physicsScene) { } } +// ============================================================================================================ public class BSShapeAvatar : BSShape { private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";