public override CollisionShape GetCollisionShape() { if (collisionShapePtr == null) { Vector3[] verts = hullMesh.vertices; int[] tris = hullMesh.triangles; //todo test for convex. Make convex if not. TriangleMesh tm = new TriangleMesh(); for (int i = 0; i < tris.Length; i += 3) { tm.AddTriangle(verts[tris[i]].ToBullet(), verts[tris[i + 1]].ToBullet(), verts[tris[i + 2]].ToBullet(), true); } collisionShapePtr = new ConvexTriangleMeshShape(tm); ((ConvexTriangleMeshShape)collisionShapePtr).LocalScaling = m_localScaling.ToBullet(); } return collisionShapePtr; }
public BulletTriangleMesh(IModelo model, Vector3 pos, Matrix rotation, Vector3 scale) { TriangleMesh TriangleMesh = new BulletSharp.TriangleMesh(true, false); Vector3[] vertices = null; int[] indices = null; ExtractData(ref vertices, ref indices, model); for (int i = 0; i < indices.Count(); i += 3) { TriangleMesh.AddTriangle(vertices[indices[i]], vertices[indices[i + 1]], vertices[indices[i + 2]]); } vertices = null; indices = null; BvhTriangleMeshShape = new BvhTriangleMeshShape(TriangleMesh, true, true); this.Shape = BvhTriangleMeshShape; this.Scale = scale; Shape.LocalScaling = scale; Object = LocalCreateRigidBody(0, Matrix.CreateTranslation(pos) * rotation, Shape); }
public BulletTriangleMesh(IModelo model, Vector3 pos, Matrix rotation, Vector3 scale) { TriangleMesh TriangleMesh = new BulletSharp.TriangleMesh(true,false); Vector3[] vertices = null; int[] indices = null; ExtractData(ref vertices, ref indices, model); for (int i = 0; i < indices.Count(); i+=3) { TriangleMesh.AddTriangle(vertices[indices[i]], vertices[indices[i+1]], vertices[indices[i+2]]); } vertices = null; indices = null; BvhTriangleMeshShape = new BvhTriangleMeshShape(TriangleMesh, true, true); this.Shape = BvhTriangleMeshShape; this.Scale = scale; Shape.LocalScaling = scale; Object = LocalCreateRigidBody(0, Matrix.CreateTranslation(pos) * rotation, Shape); }
/// <summary> /// Give it a mesh and it'll create a BulletSharp.TriangleMesh out of it /// </summary> /// <param name="mesh">The mesh you're converting</param> /// <returns>A bullet trimesh</returns> public static TriangleMesh Convert(MeshPtr mesh, Vector3 pos, Quaternion orientation, Vector3 scale) { // get our two main objects TriangleMesh BulletMesh = new TriangleMesh(true, false); Launch.Log("[Loading] Converting " + mesh.Name + " to a BulletSharp.TriangleMesh"); uint vertex_count = default(uint); Vector3[] vertices = default(Vector3[]); uint index_count = default(uint); uint[] indices = default(uint[]); GetMeshInformation(mesh, ref vertex_count, ref vertices, ref index_count, ref indices, pos, orientation, scale); BulletMesh.PreallocateIndexes((int) index_count); BulletMesh.PreallocateVertices((int) vertex_count); //BulletMesh.WeldingThreshold = 0.1f; for (int a = 0; a < index_count; a += 3) { BulletMesh.AddTriangle(vertices[indices[a]], vertices[indices[a + 1]], vertices[indices[a + 2]], true); } return BulletMesh; }
static void TestGCCollection() { var conf = new DefaultCollisionConfiguration(); var dispatcher = new CollisionDispatcher(conf); var broadphase = new DbvtBroadphase(); //var broadphase = new AxisSweep3(new Vector3(-1000, -1000, -1000), new Vector3(1000, 1000, 1000)); world = new DiscreteDynamicsWorld(dispatcher, broadphase, null, conf); world.Gravity = new Vector3(0, -10, 0); dispatcher.NearCallback = DispatcherNearCallback; CreateBody(0.0f, new BoxShape(50, 1, 50), Vector3.Zero); var dynamicObject = CreateBody(10.0f, new SphereShape(1.0f), new Vector3(2, 2, 0)); var dynamicObject2 = CreateBody(1.0f, new SphereShape(1.0f), new Vector3(0, 2, 0)); var ghostPairCallback = new GhostPairCallback(); broadphase.OverlappingPairCache.SetInternalGhostPairCallback(ghostPairCallback); AddToDisposeQueue(ghostPairCallback); ghostPairCallback = null; var ghostObject = new PairCachingGhostObject(); ghostObject.CollisionShape = new BoxShape(2); ghostObject.WorldTransform = Matrix.Translation(2,2,0); world.AddCollisionObject(ghostObject); var trimesh = new TriangleMesh(); Vector3 v0 = new Vector3(0, 0, 0); Vector3 v1 = new Vector3(1, 0, 0); Vector3 v2 = new Vector3(0, 1, 0); Vector3 v3 = new Vector3(1, 1, 0); trimesh.AddTriangle(v0, v1, v2); trimesh.AddTriangle(v1, v3, v2); var triangleMeshShape = new BvhTriangleMeshShape(trimesh, false); var triMeshObject = CreateBody(0, triangleMeshShape, new Vector3(20,0,20)); AddToDisposeQueue(triangleMeshShape); AddToDisposeQueue(trimesh); AddToDisposeQueue(triMeshObject); triangleMeshShape = null; trimesh = null; AddToDisposeQueue(conf); AddToDisposeQueue(dispatcher); AddToDisposeQueue(broadphase); AddToDisposeQueue(world); //conf.Dispose(); conf = null; //dispatcher.Dispose(); dispatcher = null; //broadphase.Dispose(); broadphase = null; world.DebugDrawer = new DebugDrawTest(); AddToDisposeQueue(world.DebugDrawer); world.SetInternalTickCallback(WorldPreTickCallback); for (int i = 0; i < 600; i++) { world.StepSimulation(1.0f / 60.0f); } world.DispatchInfo.DebugDraw = new DebugDrawTest2(); AddToDisposeQueue(world.DispatchInfo.DebugDraw); world.DispatchInfo.DebugDraw = world.DispatchInfo.DebugDraw; AddToDisposeQueue(world.DispatchInfo.DebugDraw); world.DispatchInfo.DebugDraw = null; world.DebugDrawer = null; world.DebugDrawer = new DebugDrawTest2(); world.StepSimulation(1.0f / 60.0f); world.DebugDrawWorld(); AddToDisposeQueue(world.DispatchInfo.DebugDraw); world.DebugDrawer = new DebugDrawTest(); world.DebugDrawWorld(); AddToDisposeQueue(world.DebugDrawer); world.DebugDrawer = null; TestContactTest(dynamicObject, dynamicObject2); TestGhostObjectPairs(ghostObject); TestRayCast(dynamicObject); TestTriangleMeshRayCast(triMeshObject); dynamicObject = null; dynamicObject2 = null; triMeshObject = null; //world.SetInternalTickCallback(null); world.Dispose(); world = null; GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); GC.WaitForPendingFinalizers(); TestWeakRefs(); disposeQueue.Clear(); }
public override void ConvexDecompResult(ConvexResult result) { TriangleMesh trimesh = new TriangleMesh(); demo.trimeshes.Add(trimesh); Vector3 localScaling = new Vector3(6.0f, 6.0f, 6.0f); if (output == null) return; output.WriteLine("## Hull Piece {0} with {1} vertices and {2} triangles.", mHullCount, result.mHullVertices.Length, result.mHullIndices.Length / 3); output.WriteLine("usemtl Material{0}", mBaseCount); output.WriteLine("o Object{0}", mBaseCount); foreach (Vector3 p in result.mHullVertices) { output.WriteLine(string.Format(floatFormat, "v {0:F9} {1:F9} {2:F9}", p.X, p.Y, p.Z)); } //calc centroid, to shift vertices around center of mass demo.centroid = Vector3.Zero; AlignedVector3Array vertices = new AlignedVector3Array(); if (true) { foreach (Vector3 vertex in result.mHullVertices) { demo.centroid += vertex * localScaling; } } demo.centroid /= (float)result.mHullVertices.Length; if (true) { foreach (Vector3 vertex in result.mHullVertices) { vertices.Add(vertex * localScaling - demo.centroid); } } if (true) { int[] src = result.mHullIndices; for (int i = 0; i < src.Length; i += 3) { int index0 = src[i]; int index1 = src[i + 1]; int index2 = src[i + 2]; Vector3 vertex0 = result.mHullVertices[index0] * localScaling - demo.centroid; Vector3 vertex1 = result.mHullVertices[index1] * localScaling - demo.centroid; Vector3 vertex2 = result.mHullVertices[index2] * localScaling - demo.centroid; trimesh.AddTriangle(vertex0, vertex1, vertex2); index0 += mBaseCount; index1 += mBaseCount; index2 += mBaseCount; output.WriteLine("f {0} {1} {2}", index0 + 1, index1 + 1, index2 + 1); } } //this is a tools issue: due to collision margin, convex objects overlap, compensate for it here: //#define SHRINK_OBJECT_INWARDS 1 #if SHRINK_OBJECT_INWARDS float collisionMargin = 0.01f; btAlignedObjectArray<btVector3> planeEquations; btGeometryUtil::getPlaneEquationsFromVertices(vertices,planeEquations); btAlignedObjectArray<btVector3> shiftedPlaneEquations; for (int p=0;p<planeEquations.size();p++) { btVector3 plane = planeEquations[p]; plane[3] += collisionMargin; shiftedPlaneEquations.push_back(plane); } btAlignedObjectArray<btVector3> shiftedVertices; btGeometryUtil::getVerticesFromPlaneEquations(shiftedPlaneEquations,shiftedVertices); btConvexHullShape* convexShape = new btConvexHullShape(&(shiftedVertices[0].getX()),shiftedVertices.size()); #else //SHRINK_OBJECT_INWARDS ConvexHullShape convexShape = new ConvexHullShape(vertices); #endif if (demo.sEnableSAT) { convexShape.InitializePolyhedralFeatures(); } convexShape.Margin = 0.01f; convexShapes.Add(convexShape); convexCentroids.Add(demo.centroid); demo.CollisionShapes.Add(convexShape); mBaseCount += result.mHullVertices.Length; // advance the 'base index' counter. }
protected override void OnInitializePhysics() { ManifoldPoint.ContactAdded += MyContactCallback; SetupEmptyDynamicsWorld(); WavefrontObj wo = new WavefrontObj(); int tcount = wo.LoadObj("data/file.obj"); if (tcount > 0) { TriangleMesh trimesh = new TriangleMesh(); trimeshes.Add(trimesh); Vector3 localScaling = new Vector3(6, 6, 6); List<int> indices = wo.Indices; List<Vector3> vertices = wo.Vertices; int i; for (i = 0; i < tcount; i++) { int index0 = indices[i * 3]; int index1 = indices[i * 3 + 1]; int index2 = indices[i * 3 + 2]; Vector3 vertex0 = vertices[index0] * localScaling; Vector3 vertex1 = vertices[index1] * localScaling; Vector3 vertex2 = vertices[index2] * localScaling; trimesh.AddTriangle(vertex0, vertex1, vertex2); } ConvexShape tmpConvexShape = new ConvexTriangleMeshShape(trimesh); //create a hull approximation ShapeHull hull = new ShapeHull(tmpConvexShape); float margin = tmpConvexShape.Margin; hull.BuildHull(margin); tmpConvexShape.UserObject = hull; ConvexHullShape convexShape = new ConvexHullShape(); foreach (Vector3 v in hull.Vertices) { convexShape.AddPoint(v); } if (sEnableSAT) { convexShape.InitializePolyhedralFeatures(); } tmpConvexShape.Dispose(); //hull.Dispose(); CollisionShapes.Add(convexShape); float mass = 1.0f; LocalCreateRigidBody(mass, Matrix.Translation(0, 2, 14), convexShape); const bool useQuantization = true; CollisionShape concaveShape = new BvhTriangleMeshShape(trimesh, useQuantization); LocalCreateRigidBody(0, Matrix.Translation(convexDecompositionObjectOffset), concaveShape); CollisionShapes.Add(concaveShape); // Bullet Convex Decomposition FileStream outputFile = new FileStream("file_convex.obj", FileMode.Create, FileAccess.Write); StreamWriter writer = new StreamWriter(outputFile); DecompDesc desc = new DecompDesc { mVertices = wo.Vertices.ToArray(), mTcount = tcount, mIndices = wo.Indices.ToArray(), mDepth = 5, mCpercent = 5, mPpercent = 15, mMaxVertices = 16, mSkinWidth = 0.0f }; MyConvexDecomposition convexDecomposition = new MyConvexDecomposition(writer, this); desc.mCallback = convexDecomposition; // HACD Hacd myHACD = new Hacd(); myHACD.SetPoints(wo.Vertices); myHACD.SetTriangles(wo.Indices); myHACD.CompacityWeight = 0.1; myHACD.VolumeWeight = 0.0; // HACD parameters // Recommended parameters: 2 100 0 0 0 0 int nClusters = 2; const double concavity = 100; //bool invert = false; const bool addExtraDistPoints = false; const bool addNeighboursDistPoints = false; const bool addFacesPoints = false; myHACD.NClusters = nClusters; // minimum number of clusters myHACD.VerticesPerConvexHull = 100; // max of 100 vertices per convex-hull myHACD.Concavity = concavity; // maximum concavity myHACD.AddExtraDistPoints = addExtraDistPoints; myHACD.AddNeighboursDistPoints = addNeighboursDistPoints; myHACD.AddFacesPoints = addFacesPoints; myHACD.Compute(); nClusters = myHACD.NClusters; myHACD.Save("output.wrl", false); if (true) { CompoundShape compound = new CompoundShape(); CollisionShapes.Add(compound); Matrix trans = Matrix.Identity; for (int c = 0; c < nClusters; c++) { //generate convex result Vector3[] points; int[] triangles; myHACD.GetCH(c, out points, out triangles); ConvexResult r = new ConvexResult(points, triangles); convexDecomposition.ConvexDecompResult(r); } for (i = 0; i < convexDecomposition.convexShapes.Count; i++) { Vector3 centroid = convexDecomposition.convexCentroids[i]; trans = Matrix.Translation(centroid); ConvexHullShape convexShape2 = convexDecomposition.convexShapes[i] as ConvexHullShape; compound.AddChildShape(trans, convexShape2); RigidBody body = LocalCreateRigidBody(1.0f, trans, convexShape2); } #if true mass = 10.0f; trans = Matrix.Translation(-convexDecompositionObjectOffset); RigidBody body2 = LocalCreateRigidBody(mass, trans, compound); body2.CollisionFlags |= CollisionFlags.CustomMaterialCallback; convexDecompositionObjectOffset.Z = 6; trans = Matrix.Translation(-convexDecompositionObjectOffset); body2 = LocalCreateRigidBody(mass, trans, compound); body2.CollisionFlags |= CollisionFlags.CustomMaterialCallback; convexDecompositionObjectOffset.Z = -6; trans = Matrix.Translation(-convexDecompositionObjectOffset); body2 = LocalCreateRigidBody(mass, trans, compound); body2.CollisionFlags |= CollisionFlags.CustomMaterialCallback; #endif } writer.Dispose(); outputFile.Dispose(); } }
protected override void OnInitializePhysics() { ManifoldPoint.ContactAdded += MyContactCallback; SetupEmptyDynamicsWorld(); CompoundCollisionAlgorithm.CompoundChildShapePairCallback = MyCompoundChildShapeCallback; convexDecompositionObjectOffset = new Vector3(10, 0, 0); // Load wavefront file var wo = new WavefrontObj(); int tcount = wo.LoadObj("data/file.obj"); if (tcount == 0) { return; } // Convert file data to TriangleMesh var trimesh = new TriangleMesh(); trimeshes.Add(trimesh); Vector3 localScaling = new Vector3(6, 6, 6); List<int> indices = wo.Indices; List<Vector3> vertices = wo.Vertices; int i; for (i = 0; i < tcount; i++) { int index0 = indices[i * 3]; int index1 = indices[i * 3 + 1]; int index2 = indices[i * 3 + 2]; Vector3 vertex0 = vertices[index0] * localScaling; Vector3 vertex1 = vertices[index1] * localScaling; Vector3 vertex2 = vertices[index2] * localScaling; trimesh.AddTriangleRef(ref vertex0, ref vertex1, ref vertex2); } // Create a hull approximation ConvexHullShape convexShape; using (var tmpConvexShape = new ConvexTriangleMeshShape(trimesh)) { using (var hull = new ShapeHull(tmpConvexShape)) { hull.BuildHull(tmpConvexShape.Margin); convexShape = new ConvexHullShape(hull.Vertices); } } if (sEnableSAT) { convexShape.InitializePolyhedralFeatures(); } CollisionShapes.Add(convexShape); // Add non-moving body to world float mass = 1.0f; LocalCreateRigidBody(mass, Matrix.Translation(0, 2, 14), convexShape); const bool useQuantization = true; var concaveShape = new BvhTriangleMeshShape(trimesh, useQuantization); LocalCreateRigidBody(0, Matrix.Translation(convexDecompositionObjectOffset), concaveShape); CollisionShapes.Add(concaveShape); // HACD var hacd = new Hacd(); hacd.SetPoints(wo.Vertices); hacd.SetTriangles(wo.Indices); hacd.CompacityWeight = 0.1; hacd.VolumeWeight = 0.0; // Recommended HACD parameters: 2 100 false false false hacd.NClusters = 2; // minimum number of clusters hacd.Concavity = 100; // maximum concavity hacd.AddExtraDistPoints = false; hacd.AddNeighboursDistPoints = false; hacd.AddFacesPoints = false; hacd.NumVerticesPerConvexHull = 100; // max of 100 vertices per convex-hull hacd.Compute(); hacd.Save("output.wrl", false); // Generate convex result var outputFile = new FileStream("file_convex.obj", FileMode.Create, FileAccess.Write); var writer = new StreamWriter(outputFile); var convexDecomposition = new ConvexDecomposition(writer, this); convexDecomposition.LocalScaling = localScaling; for (int c = 0; c < hacd.NClusters; c++) { Vector3[] points; int[] triangles; hacd.GetCH(c, out points, out triangles); convexDecomposition.ConvexDecompResult(points, triangles); } // Combine convex shapes into a compound shape var compound = new CompoundShape(); for (i = 0; i < convexDecomposition.convexShapes.Count; i++) { Vector3 centroid = convexDecomposition.convexCentroids[i]; var convexShape2 = convexDecomposition.convexShapes[i]; Matrix trans = Matrix.Translation(centroid); if (sEnableSAT) { convexShape2.InitializePolyhedralFeatures(); } CollisionShapes.Add(convexShape2); compound.AddChildShape(trans, convexShape2); LocalCreateRigidBody(1.0f, trans, convexShape2); } CollisionShapes.Add(compound); writer.Dispose(); outputFile.Dispose(); #if true mass = 10.0f; var body2 = LocalCreateRigidBody(mass, Matrix.Translation(-convexDecompositionObjectOffset), compound); body2.CollisionFlags |= CollisionFlags.CustomMaterialCallback; convexDecompositionObjectOffset.Z = 6; body2 = LocalCreateRigidBody(mass, Matrix.Translation(-convexDecompositionObjectOffset), compound); body2.CollisionFlags |= CollisionFlags.CustomMaterialCallback; convexDecompositionObjectOffset.Z = -6; body2 = LocalCreateRigidBody(mass, Matrix.Translation(-convexDecompositionObjectOffset), compound); body2.CollisionFlags |= CollisionFlags.CustomMaterialCallback; #endif }
public void ConvexDecompResult(Vector3[] hullVertices, int[] hullIndices) { if (output == null) return; output.WriteLine("## Hull Piece {0} with {1} vertices and {2} triangles.", convexShapes.Count, hullVertices.Length, hullIndices.Length / 3); output.WriteLine("usemtl Material{0}", mBaseCount); output.WriteLine("o Object{0}", mBaseCount); foreach (Vector3 p in hullVertices) { output.WriteLine(string.Format(floatFormat, "v {0:F9} {1:F9} {2:F9}", p.X, p.Y, p.Z)); } // Calc centroid, to shift vertices around center of mass Vector3 centroid = Vector3.Zero; foreach (Vector3 vertex in hullVertices) { centroid += vertex * LocalScaling; } centroid /= (float)hullVertices.Length; List<Vector3> outVertices = new List<Vector3>(); foreach (Vector3 vertex in hullVertices) { outVertices.Add(vertex * LocalScaling - centroid); } // Create TriangleMesh var trimesh = new TriangleMesh(); for (int i = 0; i < hullIndices.Length; i += 3) { int index0 = hullIndices[i]; int index1 = hullIndices[i + 1]; int index2 = hullIndices[i + 2]; Vector3 vertex0 = hullVertices[index0] * LocalScaling - centroid; Vector3 vertex1 = hullVertices[index1] * LocalScaling - centroid; Vector3 vertex2 = hullVertices[index2] * LocalScaling - centroid; index0 += mBaseCount; index1 += mBaseCount; index2 += mBaseCount; output.WriteLine("f {0} {1} {2}", index0 + 1, index1 + 1, index2 + 1); } //this is a tools issue: due to collision margin, convex objects overlap, compensate for it here: //#define SHRINK_OBJECT_INWARDS 1 #if SHRINK_OBJECT_INWARDS float collisionMargin = 0.01f; AlignedVector3Array planeEquations; GeometryUtil.GetPlaneEquationsFromVertices(hullVertices, planeEquations); AlignedVector3Array shiftedPlaneEquations; for (int p=0;p<planeEquations.Count;p++) { Vector3 plane = planeEquations[p]; plane[3] += collisionMargin; shiftedPlaneEquations.Add(plane); } AlignedVector3Array shiftedVertices; GeometryUtil.GetVerticesFromPlaneEquations(shiftedPlaneEquations, shiftedVertices); ConvexHullShape convexShape = new ConvexHullShape(shiftedVertices); #else //SHRINK_OBJECT_INWARDS ConvexHullShape convexShape = new ConvexHullShape(outVertices); #endif convexShape.Margin = 0.01f; convexShapes.Add(convexShape); convexCentroids.Add(centroid); mBaseCount += hullVertices.Length; // advance the 'base index' counter. }
CollisionShape bulletGetCollisionShape(Shape shape, SceneNode node) { switch (shape) { case Shape.Box: { return new BoxShape(node.BoundingBox.Extent.X / 2); } case Shape.Shpere: { return new SphereShape(node.BoundingBox.Extent.X / 2); } case Shape.Mesh: { MeshSceneNode meshNode = node as MeshSceneNode; if (meshNode == null) throw new ArgumentException(); TriangleMesh triangleMesh = new TriangleMesh(); for (int i = 0; i < meshNode.Mesh.MeshBufferCount; i++) { MeshBuffer b = meshNode.Mesh.GetMeshBuffer(i); ushort[] inds = b.Indices as ushort[]; Vertex3DTTCoords[] verts = b.Vertices as Vertex3DTTCoords[]; if (inds == null || verts == null) throw new ArgumentException(); for (int j = 0; j < inds.Length; j += 3) { Vector3Df v0 = verts[inds[j + 0]].Position; Vector3Df v1 = verts[inds[j + 1]].Position; Vector3Df v2 = verts[inds[j + 2]].Position; triangleMesh.AddTriangle( new Vector3(v0.X, v0.Y, v0.Z), new Vector3(v1.X, v1.Y, v1.Z), new Vector3(v2.X, v2.Y, v2.Z)); } } return new BvhTriangleMeshShape(triangleMesh, false); } default: throw new ArgumentException(); } }
protected override void OnInitializePhysics() { ManifoldPoint.ContactAdded += MyContactCallback; SetupEmptyDynamicsWorld(); //CompoundCollisionAlgorithm.CompoundChildShapePairCallback = MyCompoundChildShapeCallback; convexDecompositionObjectOffset = new Vector3(10, 0, 0); // Load wavefront file var wo = new WavefrontObj(); //string filename = UnityEngine.Application.dataPath + "/BulletUnity/Examples/Scripts/BulletSharpDemos/ConvexDecompositionDemo/data/file.obj"; UnityEngine.TextAsset bytes = (UnityEngine.TextAsset)UnityEngine.Resources.Load("file.obj"); System.IO.Stream byteStream = new System.IO.MemoryStream(bytes.bytes); int tcount = wo.LoadObj(byteStream); if (tcount == 0) { return; } // Convert file data to TriangleMesh var trimesh = new TriangleMesh(); trimeshes.Add(trimesh); Vector3 localScaling = new Vector3(6, 6, 6); List<int> indices = wo.Indices; List<Vector3> vertices = wo.Vertices; int i; for (i = 0; i < tcount; i++) { int index0 = indices[i * 3]; int index1 = indices[i * 3 + 1]; int index2 = indices[i * 3 + 2]; Vector3 vertex0 = vertices[index0] * localScaling; Vector3 vertex1 = vertices[index1] * localScaling; Vector3 vertex2 = vertices[index2] * localScaling; trimesh.AddTriangleRef(ref vertex0, ref vertex1, ref vertex2); } // Create a hull approximation ConvexHullShape convexShape; using (var tmpConvexShape = new ConvexTriangleMeshShape(trimesh)) { using (var hull = new ShapeHull(tmpConvexShape)) { hull.BuildHull(tmpConvexShape.Margin); convexShape = new ConvexHullShape(hull.Vertices); } } if (sEnableSAT) { convexShape.InitializePolyhedralFeatures(); } CollisionShapes.Add(convexShape); // Add non-moving body to world float mass = 1.0f; LocalCreateRigidBody(mass, Matrix.Translation(0, 2, 14), convexShape); const bool useQuantization = true; var concaveShape = new BvhTriangleMeshShape(trimesh, useQuantization); LocalCreateRigidBody(0, Matrix.Translation(convexDecompositionObjectOffset), concaveShape); CollisionShapes.Add(concaveShape); // HACD var hacd = new Hacd(); hacd.SetPoints(wo.Vertices); hacd.SetTriangles(wo.Indices); hacd.CompacityWeight = 0.1; hacd.VolumeWeight = 0.0; // Recommended HACD parameters: 2 100 false false false hacd.NClusters = 2; // minimum number of clusters hacd.Concavity = 100; // maximum concavity hacd.AddExtraDistPoints = false; hacd.AddNeighboursDistPoints = false; hacd.AddFacesPoints = false; hacd.NVerticesPerCH = 100; // max of 100 vertices per convex-hull hacd.Compute(); hacd.Save("output.wrl", false); // Generate convex result var outputFile = new FileStream("file_convex.obj", FileMode.Create, FileAccess.Write); var writer = new StreamWriter(outputFile); var convexDecomposition = new ConvexDecomposition(writer, this); convexDecomposition.LocalScaling = localScaling; for (int c = 0; c < hacd.NClusters; c++) { int nVertices = hacd.GetNPointsCH(c); int trianglesLen = hacd.GetNTrianglesCH(c) * 3; double[] points = new double[nVertices * 3]; long[] triangles = new long[trianglesLen]; hacd.GetCH(c, points, triangles); if (trianglesLen == 0) { continue; } Vector3[] verticesArray = new Vector3[nVertices]; int vi3 = 0; for (int vi = 0; vi < nVertices; vi++) { verticesArray[vi] = new Vector3( (float)points[vi3], (float)points[vi3 + 1], (float)points[vi3 + 2]); vi3 += 3; } int[] trianglesInt = new int[trianglesLen]; for (int ti = 0; ti < trianglesLen; ti++) { trianglesInt[ti] = (int)triangles[ti]; } convexDecomposition.ConvexDecompResult(verticesArray, trianglesInt); } // Combine convex shapes into a compound shape var compound = new CompoundShape(); for (i = 0; i < convexDecomposition.convexShapes.Count; i++) { Vector3 centroid = convexDecomposition.convexCentroids[i]; var convexShape2 = convexDecomposition.convexShapes[i]; Matrix trans = Matrix.Translation(centroid); if (sEnableSAT) { convexShape2.InitializePolyhedralFeatures(); } CollisionShapes.Add(convexShape2); compound.AddChildShape(trans, convexShape2); LocalCreateRigidBody(1.0f, trans, convexShape2); } CollisionShapes.Add(compound); writer.Dispose(); outputFile.Dispose(); #if true mass = 10.0f; var body2 = LocalCreateRigidBody(mass, Matrix.Translation(-convexDecompositionObjectOffset), compound); body2.CollisionFlags |= CollisionFlags.CustomMaterialCallback; convexDecompositionObjectOffset.Z = 6; body2 = LocalCreateRigidBody(mass, Matrix.Translation(-convexDecompositionObjectOffset), compound); body2.CollisionFlags |= CollisionFlags.CustomMaterialCallback; convexDecompositionObjectOffset.Z = -6; body2 = LocalCreateRigidBody(mass, Matrix.Translation(-convexDecompositionObjectOffset), compound); body2.CollisionFlags |= CollisionFlags.CustomMaterialCallback; #endif }