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);
        }
Esempio n. 3
0
    /// <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);
    }
Esempio n. 4
0
        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);
        }
Esempio n. 5
0
        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();
        }
Esempio n. 6
0
        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();
        }
Esempio n. 7
0
        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);
        }
Esempio n. 8
0
        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);
        }
Esempio n. 9
0
 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);
         }
     }
 }
Esempio n. 10
0
        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);
        }
Esempio n. 11
0
        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);
            }
        }
Esempio n. 12
0
        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();
            }
        }
Esempio n. 13
0
    /// <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);
        }
    }
Esempio n. 14
0
        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
        }