public static void CreateConvexHull(ConvexHullShape shape, Mesh mesh) { ShapeHull hull = new ShapeHull(shape); hull.BuildHull(shape.Margin); List <UnityEngine.Vector3> verts = new List <UnityEngine.Vector3>(); List <int> tris = new List <int>(); //int vertexCount = hull.NumVertices; UIntArray indices = hull.Indices; Vector3Array points = hull.Vertices; for (int i = 0; i < indices.Count; i += 3) { verts.Add(points[(int)indices[i]].ToUnity()); verts.Add(points[(int)indices[i + 1]].ToUnity()); verts.Add(points[(int)indices[i + 2]].ToUnity()); tris.Add(i); tris.Add(i + 1); tris.Add(i + 2); } mesh.vertices = verts.ToArray(); mesh.triangles = tris.ToArray(); mesh.RecalculateBounds(); mesh.RecalculateNormals(); }
public static Vector3[] CreateConvexHull(ConvexHullShape shape) { var hull = new ShapeHull(shape); hull.BuildHull(shape.Margin); int vertexCount = hull.NumIndices; UIntArray indices = hull.Indices; Vector3Array points = hull.Vertices; var vertices = new Vector3[vertexCount * 2]; int v = 0; for (int i = 0; i < vertexCount; i += 3) { Vector3 v0 = points[(int)indices[i]]; Vector3 v1 = points[(int)indices[i + 1]]; Vector3 v2 = points[(int)indices[i + 2]]; Vector3 v01 = v0 - v1; Vector3 v02 = v0 - v2; Vector3 normal = Vector3.Cross(v01, v02); normal.Normalize(); vertices[v++] = v0; vertices[v++] = normal; vertices[v++] = v1; vertices[v++] = normal; vertices[v++] = v2; vertices[v++] = normal; } return(vertices); }
/// <summary> /// Generates a convex hull collision mesh from the given original mesh. /// </summary> /// <param name="original"></param> /// <returns></returns> public static Mesh GenerateCollisionMesh(Mesh original, Vector3 offset = default(Vector3)) { ConvexHullShape tempShape = new ConvexHullShape(Array.ConvertAll(original.vertices, x => x.ToBullet()), original.vertices.Length); tempShape.Margin = 0f; ShapeHull shapeHull = new ShapeHull(tempShape); bool b = shapeHull.BuildHull(0f); Mesh collisionMesh = new Mesh(); Vector3[] vertices = new Vector3[shapeHull.NumVertices]; for (int i = 0; i < vertices.Length; i++) { vertices[i] = shapeHull.Vertices[i].ToUnity() - offset; } int[] triangles = new int[shapeHull.NumIndices]; for (int i = 0; i < triangles.Length; i++) { triangles[i] = (int)shapeHull.Indices[i]; } collisionMesh.vertices = vertices; collisionMesh.triangles = triangles; collisionMesh.RecalculateNormals(); collisionMesh.RecalculateBounds(); // TODO: Find a way to implement embedded margins. See https://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=2358 return(collisionMesh); }
public override void SetupFromMesh(Mesh mesh) { var triMesh = new TriangleMesh(); int i = 0; var vertices = mesh.Vertices; while (i < mesh.Indices.Length) { triMesh.AddTriangle( vertices[mesh.Indices[i++]], vertices[mesh.Indices[i++]], vertices[mesh.Indices[i++]] ); } var tempShape = new ConvexTriangleMeshShape(triMesh); using var tempHull = new ShapeHull(tempShape); tempHull.BuildHull(tempShape.Margin); collisionShape = new ConvexHullShape(tempHull.Vertices); }
public static void CreateConvexHull(ConvexHullShape shape, Mesh mesh) { ShapeHull hull = new ShapeHull(shape); hull.BuildHull(shape.Margin); int vertexCount = hull.NumIndices; UIntArray indices = hull.Indices; Vector3Array points = hull.Vertices; UnityEngine.Vector3[] vertices = new UnityEngine.Vector3[vertexCount]; for (int i = 0; i < vertexCount; i++) { vertices[i] = points[(int)indices[i]].ToUnity(); } int[] tris = new int[indices.Count]; for (int i = 0; i < indices.Count; i++) { tris[i] = (int)indices[i]; } mesh.vertices = vertices; mesh.triangles = tris; mesh.RecalculateBounds(); mesh.RecalculateNormals(); }
private static void CreateHullGizmoMesh(ConvexHullShape shape, ref Mesh mesh) { if (mesh == null) { mesh = new Mesh(); } else { mesh.Clear(); } Vector3[] vertexBuffer; int[] triangleBuffer; using (ShapeHull hull = new ShapeHull(shape)) { hull.BuildHull(0.0f); vertexBuffer = hull.Vertices .Select(v => v.ToUnity()) .ToArray(); triangleBuffer = hull.Indices .Select(i => (int)i) .ToArray(); } MergeVertices(vertexBuffer, 0.05f); mesh.vertices = vertexBuffer; mesh.triangles = triangleBuffer; mesh.RecalculateBounds(); mesh.RecalculateNormals(); }
Mesh CreateConvexHullShape(ConvexHullShape shape) { ShapeHull hull = new ShapeHull(shape); hull.BuildHull(shape.Margin); UIntArray hullIndices = hull.Indices; Vector3Array points = hull.Vertices; int vertexCount = hull.NumIndices; int faceCount = hull.NumTriangles; bool index32 = vertexCount > 65536; Mesh mesh = new Mesh(device, faceCount, vertexCount, MeshFlags.SystemMemory | (index32 ? MeshFlags.Use32Bit : 0), VertexFormat.Position | VertexFormat.Normal); SlimDX.DataStream indices = mesh.LockIndexBuffer(LockFlags.Discard); int i; if (index32) { for (i = 0; i < vertexCount; i++) { indices.Write(i); } } else { for (i = 0; i < vertexCount; i++) { indices.Write((short)i); } } mesh.UnlockIndexBuffer(); SlimDX.DataStream verts = mesh.LockVertexBuffer(LockFlags.Discard); Vector3 scale = Vector3.Multiply(shape.LocalScaling, 1.0f + shape.Margin); for (i = 0; i < vertexCount; i += 3) { verts.Write(Vector3.Modulate(points[(int)hullIndices[i]], scale)); verts.Position += 12; verts.Write(Vector3.Modulate(points[(int)hullIndices[i + 1]], scale)); verts.Position += 12; verts.Write(Vector3.Modulate(points[(int)hullIndices[i + 2]], scale)); verts.Position += 12; } mesh.UnlockVertexBuffer(); mesh.ComputeNormals(); shapes.Add(shape, mesh); return(mesh); }
ShapeData CreateConvexHullShape(ConvexHullShape shape) { ConvexPolyhedron poly = shape.ConvexPolyhedron; if (poly != null) { throw new NotImplementedException(); } ShapeHull hull = new ShapeHull(shape); hull.BuildHull(shape.Margin); int indexCount = hull.NumIndices; UIntArray indices = hull.Indices; Vector3Array points = hull.Vertices; ShapeData shapeData = new ShapeData(); shapeData.VertexCount = indexCount; Vector3[] vertices = new Vector3[indexCount * 2]; int v = 0, i; for (i = 0; i < indexCount; i += 3) { Vector3 v0 = points[(int)indices[i]]; Vector3 v1 = points[(int)indices[i + 1]]; Vector3 v2 = points[(int)indices[i + 2]]; Vector3 v01 = v0 - v1; Vector3 v02 = v0 - v2; Vector3 normal = Vector3.Cross(v01, v02); normal.Normalize(); vertices[v++] = v0; vertices[v++] = normal; vertices[v++] = v1; vertices[v++] = normal; vertices[v++] = v2; vertices[v++] = normal; } shapeData.SetVertexBuffer(device, vertices); return(shapeData); }
private ConvexHullShape CreateHullApproximation(TriangleMesh triangleMesh) { using (var tmpConvexShape = new ConvexTriangleMeshShape(triangleMesh)) { using (var hull = new ShapeHull(tmpConvexShape)) { hull.BuildHull(tmpConvexShape.Margin); var convexShape = new ConvexHullShape(hull.Vertices); if (_enableSat) { convexShape.InitializePolyhedralFeatures(); } return(convexShape); } } }
private static CollisionShape loadConvexHull(Mesh mesh, Vector3 scale) { TriangleMesh trimesh = new TriangleMesh(); // Shift vertices in so margin is not visible Vector3 shift = Vector3.Normalize(scale) - new Vector3(0.04f); for (int i = 0; i < mesh.submeshes[0].vertex_data.Length; i += 3) { int index0 = (int)mesh.submeshes[0].index_data[i]; int index1 = (int)mesh.submeshes[0].index_data[i + 1]; int index2 = (int)mesh.submeshes[0].index_data[i + 2]; Vector3 vertex0 = new Vector3(mesh.submeshes[0].vertex_data[index0].position.X, mesh.submeshes[0].vertex_data[index0].position.Y, mesh.submeshes[0].vertex_data[index0].position.Z) * (scale); //vertex0 *= shift; Vector3 vertex1 = new Vector3(mesh.submeshes[0].vertex_data[index1].position.X, mesh.submeshes[0].vertex_data[index1].position.Y, mesh.submeshes[0].vertex_data[index1].position.Z) * (scale); //vertex1 *= shift; Vector3 vertex2 = new Vector3(mesh.submeshes[0].vertex_data[index2].position.X, mesh.submeshes[0].vertex_data[index2].position.Y, mesh.submeshes[0].vertex_data[index2].position.Z) * (scale); //vertex2 *= shift; trimesh.AddTriangle(vertex0, vertex1, vertex2); } ConvexShape tmpShape = new ConvexTriangleMeshShape(trimesh); ShapeHull hull = new ShapeHull(tmpShape); float margin = tmpShape.Margin; hull.BuildHull(margin); tmpShape.UserObject = hull; ConvexHullShape convexShape = new ConvexHullShape(); foreach (Vector3 v in hull.Vertices) { convexShape.AddPoint(v); } hull.Dispose(); tmpShape.Dispose(); return(convexShape); }
public IConvexHullShapeImp AddConvexHullShape(float3[] points, bool optimized) { var btPoints = new Vector3[points.Count()]; for (int i = 0; i < btPoints.Count(); i++) { var point = Translater.Float3ToBtVector3(points[i]); btPoints[i] = point; } var btConvexHullShape = new ConvexHullShape(btPoints); //btConvexHullShape.LocalScaling = new Vector3(3, 3, 3); if (optimized == true) { var btShapeHull = new ShapeHull(btConvexHullShape); var margin = btConvexHullShape.Margin; btShapeHull.BuildHull(margin); ConvexHullShape simplifiedConvexShape = new ConvexHullShape(btShapeHull.Vertices); BtCollisionShapes.Add(simplifiedConvexShape); var retval = new ConvexHullShapeImp(); retval.BtConvexHullShape = simplifiedConvexShape; simplifiedConvexShape.UserObject = retval; return(retval); } else { BtCollisionShapes.Add(btConvexHullShape); var retval = new ConvexHullShapeImp(); retval.BtConvexHullShape = btConvexHullShape; btConvexHullShape.UserObject = retval; return(retval); } }
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(); } }
/// <summary> /// Generates a convex hull collision mesh from the given original mesh. /// </summary> /// <param name="original"></param> /// <returns></returns> public static Mesh GenerateCollisionMesh(Mesh original, Vector3 offset = default(Vector3), float margin = 0f) { if (margin > 0f) { ConvexHullShape tempShape = new ConvexHullShape(Array.ConvertAll(original.vertices, x => x.ToBullet()), original.vertices.Length); tempShape.Margin = 0f; ShapeHull shapeHull = new ShapeHull(tempShape); bool b = shapeHull.BuildHull(0f); AlignedVector3Array initialVertices = new AlignedVector3Array(); for (int i = 0; i < shapeHull.NumVertices; i++) { initialVertices.Add(shapeHull.Vertices[i]); } List <BulletSharp.Math.Vector4> planeEquations = GeometryUtilEx.GetPlaneEquationsFromVertices(initialVertices); List <BulletSharp.Math.Vector4> shiftedPlaneEquations = new List <BulletSharp.Math.Vector4>(); for (int i = 0; i < planeEquations.Count; i++) { BulletSharp.Math.Vector4 plane = planeEquations[i]; plane.W += margin; shiftedPlaneEquations.Add(plane); } List <BulletSharp.Math.Vector3> shiftedVertices = GeometryUtilEx.GetVerticesFromPlaneEquations(shiftedPlaneEquations); Vector3[] finalVertices = new Vector3[shiftedVertices.Count]; Mesh collisionMesh = new Mesh(); for (int i = 0; i < finalVertices.Length; i++) { finalVertices[i] = shiftedVertices[i].ToUnity() - offset; } collisionMesh.vertices = finalVertices; collisionMesh.RecalculateBounds(); return(collisionMesh); } else { ConvexHullShape tempShape = new ConvexHullShape(Array.ConvertAll(original.vertices, x => x.ToBullet()), original.vertices.Length); tempShape.Margin = 0f; ShapeHull shapeHull = new ShapeHull(tempShape); bool b = shapeHull.BuildHull(0f); Mesh collisionMesh = new Mesh(); Vector3[] vertices = new Vector3[shapeHull.NumVertices]; for (int i = 0; i < vertices.Length; i++) { vertices[i] = shapeHull.Vertices[i].ToUnity() - offset; } int[] triangles = new int[shapeHull.NumIndices]; for (int i = 0; i < triangles.Length; i++) { triangles[i] = (int)shapeHull.Indices[i]; } collisionMesh.vertices = vertices; collisionMesh.triangles = triangles; collisionMesh.RecalculateNormals(); collisionMesh.RecalculateBounds(); return(collisionMesh); } }
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 }
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]; Matrix trans = Matrix.Translation(centroid); var convexShape2 = convexDecomposition.convexShapes[i] as ConvexHullShape; 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 }