private static extern bool GetHullInfo(uint uHullIndex, ref SConvexDecompositionHullInfo infoOut);
        private static bool ComputeHull(GameObject gameObject, FracturedObject.ECCAlgorithm eAlgorithm, int nMaxHulls, int nMaxHullVertices, int nLegacySteps, bool bVerbose, out int nTotalTrianglesOut)
        {
            MeshFilter theMesh = (MeshFilter)gameObject.GetComponent<MeshFilter>();

            DllInit(true);
            SetLogFunctionPointer(Marshal.GetFunctionPointerForDelegate(new LogDelegate(Log)));

            SConvexDecompositionInfoInOut info = new SConvexDecompositionInfoInOut();

            nTotalTrianglesOut = 0;

            if(theMesh)
            {
                if(theMesh.sharedMesh)
                {
                    uint uLegacySteps = (uint)(Mathf.Max(1, nLegacySteps));

                    info.uMaxHullVertices        = (uint)(Mathf.Max(3, nMaxHullVertices));
	                info.uMaxHulls               = (uint)nMaxHulls;
	                info.fPrecision              = 0.2f;
                    info.fBackFaceDistanceFactor = 0.2f;
                    info.uLegacyDepth            = eAlgorithm == FracturedObject.ECCAlgorithm.Legacy ? uLegacySteps : 0;
                    info.uNormalizeInputMesh     = 0;
                    info.uUseFastVersion         = eAlgorithm == FracturedObject.ECCAlgorithm.Fast ? (uint)1 : (uint)0;

	                info.uTriangleCount          = (uint)theMesh.sharedMesh.triangles.Length / 3;
                    info.uVertexCount            = (uint)theMesh.sharedMesh.vertexCount;

                    Vector3[] av3Vertices = theMesh.sharedMesh.vertices;

                    if(DoConvexDecomposition(ref info, av3Vertices, theMesh.sharedMesh.triangles))
                    {
                        for(int nHull = 0; nHull < info.nHullsOut; nHull++)
                        {
                            SConvexDecompositionHullInfo hullInfo = new SConvexDecompositionHullInfo();
                            GetHullInfo((uint)nHull, ref hullInfo);

                            if(hullInfo.nTriangleCount > 0)
                            {
							    Vector3[] hullVertices = new Vector3[hullInfo.nVertexCount];
                                int[]     hullIndices  = new int[hullInfo.nTriangleCount * 3];
							
							    float fHullVolume = -1.0f;

                                FillHullMeshData((uint)nHull, ref fHullVolume, hullIndices, hullVertices);

                                Mesh hullMesh = new Mesh();
                                hullMesh.vertices  = hullVertices;
                                hullMesh.triangles = hullIndices;
                                hullMesh.uv        = new Vector2[hullVertices.Length];
                                hullMesh.RecalculateNormals();

                                GameObject goNewHull = new GameObject("Hull " + (nHull + 1));
                                goNewHull.transform.position   = gameObject.transform.position;
                                goNewHull.transform.rotation   = gameObject.transform.rotation;
                                goNewHull.transform.localScale = gameObject.transform.localScale;
                                goNewHull.transform.parent     = gameObject.transform;
                                goNewHull.layer                = gameObject.layer;
                                MeshCollider meshCollider = goNewHull.AddComponent<MeshCollider>() as MeshCollider;

                                meshCollider.sharedMesh = null;
							    meshCollider.sharedMesh = hullMesh;
							    meshCollider.convex     = true;

                                nTotalTrianglesOut += hullInfo.nTriangleCount;
                            }
                            else
                            {
                                if(bVerbose)
                                {
                                    Debug.LogWarning(gameObject.name + ": Error generating collider. ComputeHull() returned 0 triangles.");
                                }
                            }
                        }

                        if(info.nHullsOut < 0 && bVerbose)
                        {
                            Debug.LogWarning(gameObject.name + ": Error generating collider. ComputeHull() returned no hulls.");
                        }
                    }
                    else
                    {
                        if(bVerbose)
                        {
                            Debug.LogWarning(gameObject.name + ": Error generating collider. ComputeHull() returned false.");
                        }
                    }
                }
            }

            DllClose();
            return nTotalTrianglesOut > 0;
        }
Example #3
0
    public void ComputeHullsRuntime(LogDelegate log, ProgressDelegate progress)
    {
        string strMeshAssetPath = "";


        MeshFilter theMesh = (MeshFilter)gameObject.GetComponent <MeshFilter>();

        bool bForceNoMultithreading = ForceNoMultithreading;

        if (Algorithm == EAlgorithm.Legacy)
        {
            // Force no multithreading for the legacy method since sometimes it hangs when merging hulls
            bForceNoMultithreading = true;
        }

        DllInit(!bForceNoMultithreading);

        if (log != null)
        {
            SetLogFunctionPointer(Marshal.GetFunctionPointerForDelegate(log));
        }
        else
        {
            SetLogFunctionPointer(IntPtr.Zero);
        }

        if (progress != null)
        {
            SetProgressFunctionPointer(Marshal.GetFunctionPointerForDelegate(progress));
        }
        else
        {
            SetProgressFunctionPointer(IntPtr.Zero);
        }

        SConvexDecompositionInfoInOut info = new SConvexDecompositionInfoInOut();

        int nMeshCount = 0;

        if (theMesh)
        {
            if (theMesh.sharedMesh)
            {
                info.uMaxHullVertices        = (uint)(Mathf.Max(3, MaxHullVertices));
                info.uMaxHulls               = (uint)(Mathf.Max(1, MaxHulls));
                info.fPrecision              = 1.0f - Mathf.Clamp01(Precision);
                info.fBackFaceDistanceFactor = BackFaceDistanceFactor;
                info.uLegacyDepth            = Algorithm == EAlgorithm.Legacy ? (uint)(Mathf.Max(1, LegacyDepth)) : 0;
                info.uNormalizeInputMesh     = NormalizeInputMesh == true ? (uint)1 : (uint)0;
                info.uUseFastVersion         = Algorithm == EAlgorithm.Fast ? (uint)1 : (uint)0;

                info.uTriangleCount = (uint)theMesh.sharedMesh.triangles.Length / 3;
                info.uVertexCount   = (uint)theMesh.sharedMesh.vertexCount;

                if (DebugLog)
                {
                    Debug.Log(string.Format("Processing mesh: {0} triangles, {1} vertices.", info.uTriangleCount, info.uVertexCount));
                }

                Vector3[] av3Vertices  = theMesh.sharedMesh.vertices;
                float     fMeshRescale = 1.0f;

                if (NormalizeInputMesh == false && InternalScale > 0.0f)
                {
                    av3Vertices = new Vector3[theMesh.sharedMesh.vertexCount];
                    float fMaxDistSquared = 0.0f;

                    for (int nVertex = 0; nVertex < theMesh.sharedMesh.vertexCount; nVertex++)
                    {
                        float fDistSquared = theMesh.sharedMesh.vertices[nVertex].sqrMagnitude;

                        if (fDistSquared > fMaxDistSquared)
                        {
                            fMaxDistSquared = fDistSquared;
                        }
                    }

                    fMeshRescale = InternalScale / Mathf.Sqrt(fMaxDistSquared);

                    if (DebugLog)
                    {
                        Debug.Log("Max vertex distance = " + Mathf.Sqrt(fMaxDistSquared) + ". Rescaling mesh by a factor of " + fMeshRescale);
                    }

                    for (int nVertex = 0; nVertex < theMesh.sharedMesh.vertexCount; nVertex++)
                    {
                        av3Vertices[nVertex] = theMesh.sharedMesh.vertices[nVertex] * fMeshRescale;
                    }
                }

                if (DoConvexDecomposition(ref info, av3Vertices, theMesh.sharedMesh.triangles))
                {
                    if (info.nHullsOut > 0)
                    {
                        if (DebugLog)
                        {
                            Debug.Log(string.Format("Created {0} hulls", info.nHullsOut));
                        }

                        DestroyHulls();

                        foreach (Collider collider in GetComponents <Collider>())
                        {
                            collider.enabled = false;
                        }

                        m_aGoHulls = new GameObject[info.nHullsOut];
                    }
                    else if (info.nHullsOut == 0)
                    {
                        if (log != null)
                        {
                            log("Error: No hulls were generated");
                        }
                    }
                    else
                    {
                        // -1 User cancelled
                    }

                    for (int nHull = 0; nHull < info.nHullsOut; nHull++)
                    {
                        SConvexDecompositionHullInfo hullInfo = new SConvexDecompositionHullInfo();
                        GetHullInfo((uint)nHull, ref hullInfo);

                        if (hullInfo.nTriangleCount > 0)
                        {
                            m_aGoHulls[nHull] = new GameObject("Hull " + nHull);
                            m_aGoHulls[nHull].transform.position = this.transform.position;
                            m_aGoHulls[nHull].transform.rotation = this.transform.rotation;
                            m_aGoHulls[nHull].transform.parent   = this.transform;
                            m_aGoHulls[nHull].layer = this.gameObject.layer;

                            Vector3[] hullVertices = new Vector3[hullInfo.nVertexCount];
                            int[]     hullIndices  = new int[hullInfo.nTriangleCount * 3];

                            float fHullVolume     = -1.0f;
                            float fInvMeshRescale = 1.0f / fMeshRescale;

                            FillHullMeshData((uint)nHull, ref fHullVolume, hullIndices, hullVertices);

                            if (NormalizeInputMesh == false && InternalScale > 0.0f)
                            {
                                fInvMeshRescale = 1.0f / fMeshRescale;

                                for (int nVertex = 0; nVertex < hullVertices.Length; nVertex++)
                                {
                                    hullVertices[nVertex] *= fInvMeshRescale;
                                    hullVertices[nVertex]  = Vector3.Scale(hullVertices[nVertex], transform.localScale);
                                }
                            }
                            else
                            {
                                for (int nVertex = 0; nVertex < hullVertices.Length; nVertex++)
                                {
                                    hullVertices[nVertex] = Vector3.Scale(hullVertices[nVertex], transform.localScale);
                                }
                            }

                            Mesh hullMesh = new Mesh();
                            hullMesh.vertices  = hullVertices;
                            hullMesh.triangles = hullIndices;

                            Collider hullCollider = null;

                            fHullVolume *= Mathf.Pow(fInvMeshRescale, 3.0f);

                            if (fHullVolume < MinHullVolume)
                            {
                                if (DebugLog)
                                {
                                    Debug.Log(string.Format("Hull {0} will be approximated as a box collider (volume is {1:F2})", nHull, fHullVolume));
                                }

                                MeshFilter meshf = m_aGoHulls[nHull].AddComponent <MeshFilter>();
                                meshf.sharedMesh = hullMesh;

                                // Let Unity3D compute the best fitting box (it will use the meshfilter)
                                hullCollider = m_aGoHulls[nHull].AddComponent <BoxCollider>() as BoxCollider;

                                if (CreateHullMesh == false)
                                {
                                    if (Application.isEditor && Application.isPlaying == false)
                                    {
                                        DestroyImmediate(meshf);
                                        DestroyImmediate(hullMesh);
                                    }
                                    else
                                    {
                                        Destroy(meshf);
                                        Destroy(hullMesh);
                                    }
                                }
                                else
                                {
                                    meshf.sharedMesh.RecalculateNormals();
                                    meshf.sharedMesh.uv = new Vector2[hullVertices.Length];
                                }
                            }
                            else
                            {
                                if (DebugLog)
                                {
                                    Debug.Log(string.Format("Hull {0} collider: {1} vertices and {2} triangles. Volume = {3}", nHull, hullMesh.vertexCount, hullMesh.triangles.Length / 3, fHullVolume));
                                }

                                MeshCollider meshCollider = m_aGoHulls[nHull].AddComponent <MeshCollider>() as MeshCollider;

                                meshCollider.sharedMesh             = hullMesh;
                                meshCollider.convex                 = true;
                                meshCollider.smoothSphereCollisions = SmoothSphereCollisions;

                                hullCollider = meshCollider;

                                if (CreateHullMesh)
                                {
                                    MeshFilter meshf = m_aGoHulls[nHull].AddComponent <MeshFilter>();
                                    meshf.sharedMesh = hullMesh;
                                }


                                nMeshCount++;
                            }

                            if (hullCollider)
                            {
                                hullCollider.material  = PhysMaterial;
                                hullCollider.isTrigger = IsTrigger;

                                if (hullInfo.nTriangleCount > LargestHullFaces)
                                {
                                    LargestHullFaces = hullInfo.nTriangleCount;
                                }
                                if (hullInfo.nVertexCount > LargestHullVertices)
                                {
                                    LargestHullVertices = hullInfo.nVertexCount;
                                }
                            }
                        }
                    }
                }
                else
                {
                    if (log != null)
                    {
                        log("Error: convex decomposition could not be completed due to errors");
                    }
                }
            }
            else
            {
                if (log != null)
                {
                    log("Error: " + this.name + " has no mesh");
                }
            }
        }
        else
        {
            if (log != null)
            {
                log("Error: " + this.name + " has no mesh");
            }
        }

        DllClose();
    }
Example #4
0
 private static extern bool GetHullInfo(uint uHullIndex, ref SConvexDecompositionHullInfo infoOut);
        private static bool ComputeHull(GameObject gameObject, bool isTrigger, FracturedObject.ECCAlgorithm eAlgorithm, int nMaxHulls, int nMaxHullVertices, int nLegacySteps, bool bVerbose, out int nTotalTrianglesOut)
        {
            MeshFilter theMesh = (MeshFilter)gameObject.GetComponent <MeshFilter>();

            DllInit(true);
            SetLogFunctionPointer(Marshal.GetFunctionPointerForDelegate(new LogDelegate(Log)));

            SConvexDecompositionInfoInOut info = new SConvexDecompositionInfoInOut();

            nTotalTrianglesOut = 0;

            if (theMesh)
            {
                if (theMesh.sharedMesh)
                {
                    uint uLegacySteps = (uint)(Mathf.Max(1, nLegacySteps));

                    info.uMaxHullVertices        = (uint)(Mathf.Max(3, nMaxHullVertices));
                    info.uMaxHulls               = (uint)nMaxHulls;
                    info.fPrecision              = 0.2f;
                    info.fBackFaceDistanceFactor = 0.2f;
                    info.uLegacyDepth            = eAlgorithm == FracturedObject.ECCAlgorithm.Legacy ? uLegacySteps : 0;
                    info.uNormalizeInputMesh     = 0;
                    info.uUseFastVersion         = eAlgorithm == FracturedObject.ECCAlgorithm.Fast ? (uint)1 : (uint)0;

                    info.uTriangleCount = (uint)theMesh.sharedMesh.triangles.Length / 3;
                    info.uVertexCount   = (uint)theMesh.sharedMesh.vertexCount;

                    Vector3[] av3Vertices = theMesh.sharedMesh.vertices;

                    if (DoConvexDecomposition(ref info, av3Vertices, theMesh.sharedMesh.triangles))
                    {
                        for (int nHull = 0; nHull < info.nHullsOut; nHull++)
                        {
                            SConvexDecompositionHullInfo hullInfo = new SConvexDecompositionHullInfo();
                            GetHullInfo((uint)nHull, ref hullInfo);

                            if (hullInfo.nTriangleCount > 0)
                            {
                                Vector3[] hullVertices = new Vector3[hullInfo.nVertexCount];
                                int[]     hullIndices  = new int[hullInfo.nTriangleCount * 3];

                                float fHullVolume = -1.0f;

                                FillHullMeshData((uint)nHull, ref fHullVolume, hullIndices, hullVertices);

                                Mesh hullMesh = new Mesh();
                                hullMesh.vertices  = hullVertices;
                                hullMesh.triangles = hullIndices;
                                hullMesh.uv        = new Vector2[hullVertices.Length];
                                hullMesh.RecalculateNormals();

                                GameObject goNewHull = new GameObject("Hull " + (nHull + 1));
                                goNewHull.transform.position   = gameObject.transform.position;
                                goNewHull.transform.rotation   = gameObject.transform.rotation;
                                goNewHull.transform.localScale = gameObject.transform.localScale;
                                goNewHull.transform.parent     = gameObject.transform;
                                goNewHull.layer = gameObject.layer;
                                MeshCollider meshCollider = goNewHull.AddComponent <MeshCollider>() as MeshCollider;

                                meshCollider.sharedMesh = null;
                                meshCollider.sharedMesh = hullMesh;
                                meshCollider.convex     = true;

                                meshCollider.isTrigger = isTrigger;

                                nTotalTrianglesOut += hullInfo.nTriangleCount;
                            }
                            else
                            {
                                if (bVerbose)
                                {
                                    Debug.LogWarning(gameObject.name + ": Error generating collider. ComputeHull() returned 0 triangles.");
                                }
                            }
                        }

                        if (info.nHullsOut < 0 && bVerbose)
                        {
                            Debug.LogWarning(gameObject.name + ": Error generating collider. ComputeHull() returned no hulls.");
                        }
                    }
                    else
                    {
                        if (bVerbose)
                        {
                            Debug.LogWarning(gameObject.name + ": Error generating collider. ComputeHull() returned false.");
                        }
                    }
                }
            }

            DllClose();
            return(nTotalTrianglesOut > 0);
        }
    public bool ComputeHulls(LogDelegate log, ProgressDelegate progress)
    {
        bool hadError = false;
        string strMeshAssetPath = "";

        if(CreateMeshAssets)
        {
            string uniqueID = null;;
            Debug.LogFormat("Obj: {0} of type {1}", gameObject.transform.FullPath(), UnityEditor.PrefabUtility.GetPrefabType(this.gameObject));
            if (UnityEditor.PrefabUtility.GetPrefabParent(this.gameObject) != null)
            {
                string prefabPath = UnityEditor.AssetDatabase.GetAssetPath(UnityEditor.PrefabUtility.GetPrefabParent(this.gameObject));
                int startIndex = 1 + prefabPath.LastIndexOf("/");
                prefabPath = prefabPath.Substring(startIndex, prefabPath.LastIndexOf(".") - startIndex);
                uniqueID = string.Format("{0}_{1}", prefabPath, UnityEditor.PrefabUtility.GetPrefabParent(this.gameObject).name);
            }
            else
                uniqueID = string.Format("{0}_{1}", gameObject.name, this.GetInstanceID().ToString());
            strMeshAssetPath = "ColliderMeshes\\" + uniqueID + " _colMesh.asset";
            if (!InBatchSaveMode)
                strMeshAssetPath = UnityEditor.EditorUtility.SaveFilePanelInProject("Save mesh asset", strMeshAssetPath, "asset", "Save collider mesh for " + gameObject.name);
            else
                strMeshAssetPath = "Assets/" + strMeshAssetPath;

            if(strMeshAssetPath.Length == 0)
            {
                return false;
            }
        }

        MeshFilter theMesh = (MeshFilter)gameObject.GetComponent<MeshFilter>();

        bool bForceNoMultithreading = ForceNoMultithreading;

        if(Algorithm == EAlgorithm.Legacy)
        {
            // Force no multithreading for the legacy method since sometimes it hangs when merging hulls
            bForceNoMultithreading = true;
        }

        SConvexDecompositionInfoInOut      info      = new SConvexDecompositionInfoInOut();
        SConvexDecompositionInfoInOutVHACD infoVHACD = new SConvexDecompositionInfoInOutVHACD();

        if(Algorithm == EAlgorithm.VHACD)
        {
            ConcaveColliderDll20.DllInit(!bForceNoMultithreading);

            if(log != null)
            {
                ConcaveColliderDll20.SetLogFunctionPointer(Marshal.GetFunctionPointerForDelegate(log));
            }
            else
            {
                ConcaveColliderDll20.SetLogFunctionPointer(IntPtr.Zero);
            }

            if(progress != null)
            {
                ConcaveColliderDll20.SetProgressFunctionPointer(Marshal.GetFunctionPointerForDelegate(progress));
            }
            else
            {
                ConcaveColliderDll20.SetProgressFunctionPointer(IntPtr.Zero);
            }
        }
        else
        {
            DllInit(!bForceNoMultithreading);

            if(log != null)
            {
                SetLogFunctionPointer(Marshal.GetFunctionPointerForDelegate(log));
            }
            else
            {
                SetLogFunctionPointer(IntPtr.Zero);
            }

            if(progress != null)
            {
                SetProgressFunctionPointer(Marshal.GetFunctionPointerForDelegate(progress));
            }
            else
            {
                SetProgressFunctionPointer(IntPtr.Zero);
            }
        }

        int nMeshCount = 0;

        bool bDllCloseVHACD = false;

        if(theMesh)
        {
            if(theMesh.sharedMesh)
            {
                if(Algorithm == EAlgorithm.VHACD)
                {
                      infoVHACD.fConcavity               = VHACD_Concavity;
                      infoVHACD.fAlpha                   = 0.05f;
                      infoVHACD.fBeta                    = 0.05f;
                      infoVHACD.fGamma                   = 0.05f;
                      infoVHACD.fDelta                   = 0.0005f;
                      infoVHACD.fMinVolumePerCH          = VHACD_MinVolumePerCH;
                      infoVHACD.uResolution              = (uint)VHACD_NumVoxels;
                      infoVHACD.uMaxNumVerticesPerCH     = (uint)VHACD_MaxVerticesPerCH;
                      infoVHACD.nDepth                   = 20;
                      infoVHACD.nPlaneDownsampling       = 4;
                      infoVHACD.nConvexhullDownsampling  = 4;
                      infoVHACD.nPca                     = VHACD_NormalizeMesh ? 1 : 0;
                      infoVHACD.nMode                    = 0;
                      infoVHACD.nConvexhullApproximation = 1;
                      infoVHACD.nOclAcceleration         = 1;

                    infoVHACD.uTriangleCount          = (uint)theMesh.sharedMesh.triangles.Length / 3;
                    infoVHACD.uVertexCount            = (uint)theMesh.sharedMesh.vertexCount;

                    if(DebugLog)
                    {
                        Debug.Log(string.Format("Processing mesh: {0} triangles, {1} vertices.", infoVHACD.uTriangleCount, infoVHACD.uVertexCount));
                    }
                }
                else
                {
                    info.uMaxHullVertices        = (uint)(Mathf.Max(3, MaxHullVertices));
                    info.uMaxHulls               = (uint)(Mathf.Max(1, MaxHulls));
                    info.fPrecision              = 1.0f - Mathf.Clamp01(Precision);
                    info.fBackFaceDistanceFactor = BackFaceDistanceFactor;
                    info.uLegacyDepth            = Algorithm == EAlgorithm.Legacy ? (uint)(Mathf.Max(1, LegacyDepth)) : 0;
                    info.uNormalizeInputMesh     = NormalizeInputMesh == true ? (uint)1 : (uint)0;
                    info.uUseFastVersion         = Algorithm == EAlgorithm.Fast ? (uint)1 : (uint)0;

                    info.uTriangleCount          = (uint)theMesh.sharedMesh.triangles.Length / 3;
                    info.uVertexCount            = (uint)theMesh.sharedMesh.vertexCount;

                    if(DebugLog)
                    {
                        Debug.Log(string.Format("Processing mesh: {0} triangles, {1} vertices.", info.uTriangleCount, info.uVertexCount));
                    }
                }

                Vector3[] av3Vertices = theMesh.sharedMesh.vertices;
                float fMeshRescale    = 1.0f;

                if(NormalizeInputMesh == false && InternalScale > 0.0f && Algorithm != EAlgorithm.VHACD)
                {
                    av3Vertices = new Vector3[theMesh.sharedMesh.vertexCount];
                    float fMaxDistSquared = 0.0f;

                    for(int nVertex = 0; nVertex < theMesh.sharedMesh.vertexCount; nVertex++)
                    {
                        float fDistSquared = theMesh.sharedMesh.vertices[nVertex].sqrMagnitude;

                        if(fDistSquared > fMaxDistSquared)
                        {
                            fMaxDistSquared = fDistSquared;
                        }
                    }

                    fMeshRescale = InternalScale / Mathf.Sqrt(fMaxDistSquared);

                    if(DebugLog)
                    {
                        Debug.Log("Max vertex distance = " + Mathf.Sqrt(fMaxDistSquared) + ". Rescaling mesh by a factor of " + fMeshRescale);
                    }

                    for(int nVertex = 0; nVertex < theMesh.sharedMesh.vertexCount; nVertex++)
                    {
                        av3Vertices[nVertex] = theMesh.sharedMesh.vertices[nVertex] * fMeshRescale;
                    }
                }

                bool bConvexDecompositionOK = false;

                int nHullsOut = 0;

                if(Algorithm == EAlgorithm.VHACD)
                {
                    bConvexDecompositionOK = ConcaveColliderDll20.DoConvexDecomposition(ref infoVHACD, av3Vertices, theMesh.sharedMesh.triangles);
                    nHullsOut = infoVHACD.nHullsOut;
                    bDllCloseVHACD = true;
                }
                else
                {
                    bConvexDecompositionOK = DoConvexDecomposition(ref info, av3Vertices, theMesh.sharedMesh.triangles);
                    nHullsOut = info.nHullsOut;
                }

                if(bConvexDecompositionOK)
                {
                    if(nHullsOut > 0)
                    {
                        if(DebugLog)
                        {
                            Debug.Log(string.Format("Created {0} hulls", nHullsOut));
                        }

                        DestroyHulls();

                        foreach(Collider collider in GetComponents<Collider>())
                        {
                            collider.enabled = false;
                        }

                        m_aGoHulls = new GameObject[nHullsOut];
                    }
                    else if(nHullsOut == 0)
                    {
                        hadError = true;
                        if(log != null) log("Error: No hulls were generated");
                    }
                    else
                    {
                        // -1 User cancelled
                        hadError = true;
                    }

                    Transform hullParent = this.transform.Find("Generated Colliders");
                    if (hullParent == null)
                    {
                        hullParent = (new GameObject("Generated Colliders")).transform;
                        hullParent.transform.SetParent(this.transform, false);
                    }

                    for(int nHull = 0; nHull < nHullsOut; nHull++)
                    {
                        SConvexDecompositionHullInfo hullInfo = new SConvexDecompositionHullInfo();

                        if(Algorithm == EAlgorithm.VHACD)
                        {
                            ConcaveColliderDll20.GetHullInfo((uint)nHull, ref hullInfo);
                        }
                        else
                        {
                            GetHullInfo((uint)nHull, ref hullInfo);
                        }

                        if(hullInfo.nTriangleCount > 0)
                        {
                            m_aGoHulls[nHull] = new GameObject("Hull " + nHull);
                            m_aGoHulls[nHull].transform.position = this.transform.position;
                            m_aGoHulls[nHull].transform.rotation = this.transform.rotation;
                            m_aGoHulls[nHull].transform.parent   = hullParent;
                            m_aGoHulls[nHull].layer              = this.gameObject.layer;

                            Vector3[] hullVertices = new Vector3[hullInfo.nVertexCount];
                            int[]     hullIndices  = new int[hullInfo.nTriangleCount * 3];

                            float fHullVolume     = -1.0f;
                            float fInvMeshRescale = 1.0f / fMeshRescale;

                            if(Algorithm == EAlgorithm.VHACD)
                            {
                                ConcaveColliderDll20.FillHullMeshData((uint)nHull, ref fHullVolume, hullIndices, hullVertices);
                            }
                            else
                            {
                                FillHullMeshData((uint)nHull, ref fHullVolume, hullIndices, hullVertices);
                            }

                            if(NormalizeInputMesh == false && InternalScale > 0.0f && Algorithm != EAlgorithm.VHACD)
                            {
                                fInvMeshRescale = 1.0f / fMeshRescale;

                                for(int nVertex = 0; nVertex < hullVertices.Length; nVertex++)
                                {
                                    hullVertices[nVertex] *= fInvMeshRescale;
                                    hullVertices[nVertex]  = Vector3.Scale(hullVertices[nVertex], transform.localScale);
                                }
                            }
                            else
                            {
                                for(int nVertex = 0; nVertex < hullVertices.Length; nVertex++)
                                {
                                    hullVertices[nVertex] = Vector3.Scale(hullVertices[nVertex], transform.localScale);
                                }
                            }

                            Mesh hullMesh = new Mesh();
                            hullMesh.vertices  = hullVertices;
                            hullMesh.triangles = hullIndices;

                            Collider hullCollider = null;

                            fHullVolume *= Mathf.Pow(fInvMeshRescale, 3.0f);

                            if(fHullVolume < MinHullVolume && Algorithm != EAlgorithm.VHACD)
                            {
                                if(DebugLog)
                                {
                                    Debug.Log(string.Format("Hull {0} will be approximated as a box collider (volume is {1:F2})", nHull, fHullVolume));
                                }

                                MeshFilter meshf = m_aGoHulls[nHull].AddComponent<MeshFilter>();
                                meshf.sharedMesh = hullMesh;

                                // Let Unity3D compute the best fitting box (it will use the meshfilter)
                                hullCollider = m_aGoHulls[nHull].AddComponent<BoxCollider>() as BoxCollider;
                                BoxCollider boxCollider = hullCollider as BoxCollider;
                                boxCollider.center = hullMesh.bounds.center;
                                boxCollider.size = hullMesh.bounds.size;

                                if(CreateHullMesh == false)
                                {
                                    if(Application.isEditor && Application.isPlaying == false)
                                    {
                                        DestroyImmediate(meshf);
                                        DestroyImmediate(hullMesh);
                                    }
                                    else
                                    {
                                        Destroy(meshf);
                                        Destroy(hullMesh);
                                    }
                                }
                                else
                                {
                                    meshf.sharedMesh.RecalculateNormals();
                                    meshf.sharedMesh.uv = new Vector2[hullVertices.Length];
                                }
                            }
                            else
                            {
                                if(DebugLog)
                                {
                                    Debug.Log(string.Format("Hull {0} collider: {1} vertices and {2} triangles. Volume = {3}", nHull, hullMesh.vertexCount, hullMesh.triangles.Length / 3, fHullVolume));
                                }

                                MeshCollider meshCollider = m_aGoHulls[nHull].AddComponent<MeshCollider>() as MeshCollider;

                                meshCollider.sharedMesh = hullMesh;
                                meshCollider.convex     = true;

                                hullCollider = meshCollider;

                                if(CreateHullMesh)
                                {
                                    MeshFilter meshf = m_aGoHulls[nHull].AddComponent<MeshFilter>();
                                    meshf.sharedMesh = hullMesh;
                                }

                                if(CreateMeshAssets)
                                {
                                    if(nMeshCount == 0)
                                    {
                                        if(progress != null)
                                        {
                                            progress("Creating mesh assets", 0.0f);
                                        }

                                        // Avoid some shader warnings
                                        hullMesh.RecalculateNormals();
                                        hullMesh.uv = new Vector2[hullVertices.Length];

                                        UnityEditor.AssetDatabase.CreateAsset(hullMesh, strMeshAssetPath);
                                    }
                                    else
                                    {
                                        if(progress != null)
                                        {
                                            progress("Creating mesh assets", nHullsOut > 1 ? (nHull / (nHullsOut - 1.0f)) * 100.0f : 100.0f);
                                        }

                                        // Avoid some shader warnings
                                        hullMesh.RecalculateNormals();
                                        hullMesh.uv = new Vector2[hullVertices.Length];

                                        UnityEditor.AssetDatabase.AddObjectToAsset(hullMesh, strMeshAssetPath);
                                        UnityEditor.AssetDatabase.ImportAsset(UnityEditor.AssetDatabase.GetAssetPath(hullMesh));
                                    }
                                }

                                nMeshCount++;
                            }

                            if(hullCollider)
                            {
                                hullCollider.material  = PhysMaterial;
                                hullCollider.isTrigger = IsTrigger;

                                if(hullInfo.nTriangleCount > LargestHullFaces)    LargestHullFaces    = hullInfo.nTriangleCount;
                                if(hullInfo.nVertexCount   > LargestHullVertices) LargestHullVertices = hullInfo.nVertexCount;
                            }
                        }
                    }

                    if(CreateMeshAssets)
                    {
                        UnityEditor.AssetDatabase.Refresh();
                    }
                }
                else
                {
                    hadError = true;
                    if(log != null) log("Error: convex decomposition could not be completed due to errors");
                }
            }
            else
            {
                hadError = true;
                if(log != null) log("Error: " + this.name + " has no mesh");
            }
        }
        else
        {
            hadError = true;
            if(log != null) log("Error: " + this.name + " has no mesh");
        }

        if(Algorithm == EAlgorithm.VHACD)
        {
            if(bDllCloseVHACD)
            {
                ConcaveColliderDll20.DllClose();
            }
        }
        else
        {
            DllClose();
        }
        return !hadError;
    }
Example #7
0
        public static int ComputeHull(GameObject gameObject, int nMaxHullVertices, bool bVerbose)
        {
            int nTotalTriangles = 0;

            MeshFilter theMesh = (MeshFilter)gameObject.GetComponent <MeshFilter>();

            DllInit(true);

            SConvexDecompositionInfoInOut info = new SConvexDecompositionInfoInOut();

            if (theMesh)
            {
                if (theMesh.sharedMesh)
                {
                    info.uMaxHullVertices        = (uint)(Mathf.Max(3, nMaxHullVertices));
                    info.uMaxHulls               = 1;
                    info.fPrecision              = 0.8f;
                    info.fBackFaceDistanceFactor = 0.2f;
                    info.uLegacyDepth            = 0;
                    info.uNormalizeInputMesh     = 0;
                    info.uUseFastVersion         = 1;

                    info.uTriangleCount = (uint)theMesh.sharedMesh.triangles.Length / 3;
                    info.uVertexCount   = (uint)theMesh.sharedMesh.vertexCount;

                    Vector3[] av3Vertices = theMesh.sharedMesh.vertices;

                    if (DoConvexDecomposition(ref info, av3Vertices, theMesh.sharedMesh.triangles))
                    {
                        for (int nHull = 0; nHull < info.nHullsOut; nHull++)
                        {
                            SConvexDecompositionHullInfo hullInfo = new SConvexDecompositionHullInfo();
                            GetHullInfo((uint)nHull, ref hullInfo);

                            if (hullInfo.nTriangleCount > 0)
                            {
                                Vector3[] hullVertices = new Vector3[hullInfo.nVertexCount];
                                int[]     hullIndices  = new int[hullInfo.nTriangleCount * 3];

                                float fHullVolume = -1.0f;

                                FillHullMeshData((uint)nHull, ref fHullVolume, hullIndices, hullVertices);

                                Mesh hullMesh = new Mesh();
                                hullMesh.vertices  = hullVertices;
                                hullMesh.triangles = hullIndices;
                                hullMesh.uv        = new Vector2[hullVertices.Length];
                                hullMesh.RecalculateNormals();

                                GameObject goNewHull = new GameObject("Hull " + (nHull + 1));
                                goNewHull.transform.position   = gameObject.transform.position;
                                goNewHull.transform.rotation   = gameObject.transform.rotation;
                                goNewHull.transform.localScale = gameObject.transform.localScale;
                                goNewHull.transform.parent     = gameObject.transform;
                                MeshCollider meshCollider = goNewHull.AddComponent <MeshCollider>() as MeshCollider;

                                meshCollider.sharedMesh = null;
                                meshCollider.sharedMesh = hullMesh;
                                meshCollider.convex     = true;

                                nTotalTriangles += hullInfo.nTriangleCount;
                            }
                            else
                            {
                                if (bVerbose)
                                {
//                                    Debug.LogWarning("Error generating collider for " + gameObject.name + ": ComputeHull() returned 0 triangles. Approximating with another collider.");
                                }
                            }
                        }

                        if (info.nHullsOut == 0 && bVerbose)
                        {
//                            Debug.LogWarning("Error generating collider for " + gameObject.name + ": ComputeHull() returned 0 hulls. Approximating with another collider.");
                        }
                    }
                    else
                    {
                        if (bVerbose)
                        {
//                            Debug.LogWarning("Error generating collider for " + gameObject.name + ": ComputeHull() returned false. Approximating with another collider.");
                        }
                    }
                }
            }

            DllClose();
            return(nTotalTriangles);
        }
Example #8
0
    public void ComputeHulls(LogDelegate log, ProgressDelegate progress)
    {
        string strMeshAssetPath = "";

        if(CreateMeshAssets)
        {
            strMeshAssetPath = UnityEditor.EditorUtility.SaveFilePanelInProject("Save mesh asset", "mesh_" + gameObject.name + this.GetInstanceID().ToString() + ".asset", "asset", "Please enter a file name to save the mesh asset to");

            if(strMeshAssetPath.Length == 0)
            {
                return;
            }
        }

        MeshFilter theMesh = (MeshFilter)gameObject.GetComponent<MeshFilter>();

        bool bForceNoMultithreading = ForceNoMultithreading;

        if(Algorithm == EAlgorithm.Legacy)
        {
            // Force no multithreading for the legacy method since sometimes it hangs when merging hulls
            bForceNoMultithreading = true;
        }

        DllInit(!bForceNoMultithreading);

        if(log != null)
        {
            SetLogFunctionPointer(Marshal.GetFunctionPointerForDelegate(log));
        }
        else
        {
            SetLogFunctionPointer(IntPtr.Zero);
        }

        if(progress != null)
        {
            SetProgressFunctionPointer(Marshal.GetFunctionPointerForDelegate(progress));
        }
        else
        {
            SetProgressFunctionPointer(IntPtr.Zero);
        }

        SConvexDecompositionInfoInOut info = new SConvexDecompositionInfoInOut();

        int nMeshCount = 0;

        if(theMesh)
        {
            if(theMesh.sharedMesh)
            {
                info.uMaxHullVertices        = (uint)(Mathf.Max(3, MaxHullVertices));
                info.uMaxHulls               = (uint)(Mathf.Max(1, MaxHulls));
                info.fPrecision              = 1.0f - Mathf.Clamp01(Precision);
                info.fBackFaceDistanceFactor = BackFaceDistanceFactor;
                info.uLegacyDepth            = Algorithm == EAlgorithm.Legacy ? (uint)(Mathf.Max(1, LegacyDepth)) : 0;
                info.uNormalizeInputMesh     = NormalizeInputMesh == true ? (uint)1 : (uint)0;
                info.uUseFastVersion         = Algorithm == EAlgorithm.Fast ? (uint)1 : (uint)0;

                info.uTriangleCount          = (uint)theMesh.sharedMesh.triangles.Length / 3;
                info.uVertexCount            = (uint)theMesh.sharedMesh.vertexCount;

                if(DebugLog)
                {
                    Debug.Log(string.Format("Processing mesh: {0} triangles, {1} vertices.", info.uTriangleCount, info.uVertexCount));
                }

                Vector3[] av3Vertices = theMesh.sharedMesh.vertices;
                float fMeshRescale    = 1.0f;

                if(NormalizeInputMesh == false && InternalScale > 0.0f)
                {
                    av3Vertices = new Vector3[theMesh.sharedMesh.vertexCount];
                    float fMaxDistSquared = 0.0f;

                    for(int nVertex = 0; nVertex < theMesh.sharedMesh.vertexCount; nVertex++)
                    {
                        float fDistSquared = theMesh.sharedMesh.vertices[nVertex].sqrMagnitude;

                        if(fDistSquared > fMaxDistSquared)
                        {
                            fMaxDistSquared = fDistSquared;
                        }
                    }

                    fMeshRescale = InternalScale / Mathf.Sqrt(fMaxDistSquared);

                    if(DebugLog)
                    {
                        Debug.Log("Max vertex distance = " + Mathf.Sqrt(fMaxDistSquared) + ". Rescaling mesh by a factor of " + fMeshRescale);
                    }

                    for(int nVertex = 0; nVertex < theMesh.sharedMesh.vertexCount; nVertex++)
                    {
                        av3Vertices[nVertex] = theMesh.sharedMesh.vertices[nVertex] * fMeshRescale;
                    }
                }

                if(DoConvexDecomposition(ref info, av3Vertices, theMesh.sharedMesh.triangles))
                {
                    if(info.nHullsOut > 0)
                    {
                        if(DebugLog)
                        {
                            Debug.Log(string.Format("Created {0} hulls", info.nHullsOut));
                        }

                        DestroyHulls();

                        foreach(Collider collider in GetComponents<Collider>())
                        {
                            collider.enabled = false;
                        }

                        m_aGoHulls = new GameObject[info.nHullsOut];
                    }
                    else if(info.nHullsOut == 0)
                    {
                        if(log != null) log("Error: No hulls were generated");
                    }
                    else
                    {
                        // -1 User cancelled
                    }

                    for(int nHull = 0; nHull < info.nHullsOut; nHull++)
                    {
                        SConvexDecompositionHullInfo hullInfo = new SConvexDecompositionHullInfo();
                        GetHullInfo((uint)nHull, ref hullInfo);

                        if(hullInfo.nTriangleCount > 0)
                        {
                            m_aGoHulls[nHull] = new GameObject("Hull " + nHull);
                            m_aGoHulls[nHull].transform.position = this.transform.position;
                            m_aGoHulls[nHull].transform.rotation = this.transform.rotation;
                            m_aGoHulls[nHull].transform.parent   = this.transform;
                            m_aGoHulls[nHull].layer              = this.gameObject.layer;

                            Vector3[] hullVertices = new Vector3[hullInfo.nVertexCount];
                            int[]     hullIndices  = new int[hullInfo.nTriangleCount * 3];

                            float fHullVolume     = -1.0f;
                            float fInvMeshRescale = 1.0f / fMeshRescale;

                            FillHullMeshData((uint)nHull, ref fHullVolume, hullIndices, hullVertices);

                            if(NormalizeInputMesh == false && InternalScale > 0.0f)
                            {
                                fInvMeshRescale = 1.0f / fMeshRescale;

                                for(int nVertex = 0; nVertex < hullVertices.Length; nVertex++)
                                {
                                    hullVertices[nVertex] *= fInvMeshRescale;
                                    hullVertices[nVertex]  = Vector3.Scale(hullVertices[nVertex], transform.localScale);
                                }
                            }
                            else
                            {
                                for(int nVertex = 0; nVertex < hullVertices.Length; nVertex++)
                                {
                                    hullVertices[nVertex] = Vector3.Scale(hullVertices[nVertex], transform.localScale);
                                }
                            }

                            Mesh hullMesh = new Mesh();
                            hullMesh.vertices  = hullVertices;
                            hullMesh.triangles = hullIndices;

                            Collider hullCollider = null;

                            fHullVolume *= Mathf.Pow(fInvMeshRescale, 3.0f);

                            if(fHullVolume < MinHullVolume)
                            {
                                if(DebugLog)
                                {
                                    Debug.Log(string.Format("Hull {0} will be approximated as a box collider (volume is {1:F2})", nHull, fHullVolume));
                                }

                                MeshFilter meshf = m_aGoHulls[nHull].AddComponent<MeshFilter>();
                                meshf.sharedMesh = hullMesh;

                                // Let Unity3D compute the best fitting box (it will use the meshfilter)
                                hullCollider = m_aGoHulls[nHull].AddComponent<BoxCollider>() as BoxCollider;
                                BoxCollider boxCollider = hullCollider as BoxCollider;
                                boxCollider.center = hullMesh.bounds.center;
                                boxCollider.size = hullMesh.bounds.size;

                                if(CreateHullMesh == false)
                                {
                                    if(Application.isEditor && Application.isPlaying == false)
                                    {
                                        DestroyImmediate(meshf);
                                        DestroyImmediate(hullMesh);
                                    }
                                    else
                                    {
                                        Destroy(meshf);
                                        Destroy(hullMesh);
                                    }
                                }
                                else
                                {
                                    meshf.sharedMesh.RecalculateNormals();
                                    meshf.sharedMesh.uv = new Vector2[hullVertices.Length];
                                }
                            }
                            else
                            {
                                if(DebugLog)
                                {
                                    Debug.Log(string.Format("Hull {0} collider: {1} vertices and {2} triangles. Volume = {3}", nHull, hullMesh.vertexCount, hullMesh.triangles.Length / 3, fHullVolume));
                                }

                                MeshCollider meshCollider = m_aGoHulls[nHull].AddComponent<MeshCollider>() as MeshCollider;

                                meshCollider.sharedMesh = hullMesh;
                                meshCollider.convex     = true;

                                hullCollider = meshCollider;

                                if(CreateHullMesh)
                                {
                                    MeshFilter meshf = m_aGoHulls[nHull].AddComponent<MeshFilter>();
                                    meshf.sharedMesh = hullMesh;
                                }

                                if(CreateMeshAssets)
                                {
                                    if(nMeshCount == 0)
                                    {
                                        if(progress != null)
                                        {
                                            progress("Creating mesh assets", 0.0f);
                                        }

                                        // Avoid some shader warnings
                                        hullMesh.RecalculateNormals();
                                        hullMesh.uv = new Vector2[hullVertices.Length];

                                        UnityEditor.AssetDatabase.CreateAsset(hullMesh, strMeshAssetPath);
                                    }
                                    else
                                    {
                                        if(progress != null)
                                        {
                                            progress("Creating mesh assets", info.nHullsOut > 1 ? (nHull / (info.nHullsOut - 1.0f)) * 100.0f : 100.0f);
                                        }

                                        // Avoid some shader warnings
                                        hullMesh.RecalculateNormals();
                                        hullMesh.uv = new Vector2[hullVertices.Length];

                                        UnityEditor.AssetDatabase.AddObjectToAsset(hullMesh, strMeshAssetPath);
                                        UnityEditor.AssetDatabase.ImportAsset(UnityEditor.AssetDatabase.GetAssetPath(hullMesh));
                                    }
                                }

                                nMeshCount++;
                            }

                            if(hullCollider)
                            {
                                hullCollider.material  = PhysMaterial;
                                hullCollider.isTrigger = IsTrigger;

                                if(hullInfo.nTriangleCount > LargestHullFaces)    LargestHullFaces    = hullInfo.nTriangleCount;
                                if(hullInfo.nVertexCount   > LargestHullVertices) LargestHullVertices = hullInfo.nVertexCount;
                            }
                        }
                    }

                    if(CreateMeshAssets)
                    {
                        UnityEditor.AssetDatabase.Refresh();
                    }
                }
                else
                {
                    if(log != null) log("Error: convex decomposition could not be completed due to errors");
                }
            }
            else
            {
                if(log != null) log("Error: " + this.name + " has no mesh");
            }
        }
        else
        {
            if(log != null) log("Error: " + this.name + " has no mesh");
        }

        DllClose();
    }
Example #9
0
        public static int ComputeHull(GameObject gameObject, int nMaxHullVertices, bool bVerbose)
        {
            int nTotalTriangles = 0;

            MeshFilter theMesh = (MeshFilter)gameObject.GetComponent<MeshFilter>();

            DllInit(true);

            SConvexDecompositionInfoInOut info = new SConvexDecompositionInfoInOut();

            if(theMesh)
            {
                if(theMesh.sharedMesh)
                {
                    info.uMaxHullVertices        = (uint)(Mathf.Max(3, nMaxHullVertices));
	                info.uMaxHulls               = 1;
	                info.fPrecision              = 0.8f;
                    info.fBackFaceDistanceFactor = 0.2f;
                    info.uLegacyDepth            = 0;
                    info.uNormalizeInputMesh     = 0;
                    info.uUseFastVersion         = 1;

	                info.uTriangleCount          = (uint)theMesh.sharedMesh.triangles.Length / 3;
                    info.uVertexCount            = (uint)theMesh.sharedMesh.vertexCount;

                    Vector3[] av3Vertices = theMesh.sharedMesh.vertices;

                    if(DoConvexDecomposition(ref info, av3Vertices, theMesh.sharedMesh.triangles))
                    {
                        for(int nHull = 0; nHull < info.nHullsOut; nHull++)
                        {
                            SConvexDecompositionHullInfo hullInfo = new SConvexDecompositionHullInfo();
                            GetHullInfo((uint)nHull, ref hullInfo);

                            if(hullInfo.nTriangleCount > 0)
                            {
							    Vector3[] hullVertices = new Vector3[hullInfo.nVertexCount];
                                int[]     hullIndices  = new int[hullInfo.nTriangleCount * 3];
							
							    float fHullVolume = -1.0f;

                                FillHullMeshData((uint)nHull, ref fHullVolume, hullIndices, hullVertices);

                                Mesh hullMesh = new Mesh();
                                hullMesh.vertices  = hullVertices;
                                hullMesh.triangles = hullIndices;
                                hullMesh.uv        = new Vector2[hullVertices.Length];
                                hullMesh.RecalculateNormals();

                                GameObject goNewHull = new GameObject("Hull " + (nHull + 1));
                                goNewHull.transform.position   = gameObject.transform.position;
                                goNewHull.transform.rotation   = gameObject.transform.rotation;
                                goNewHull.transform.localScale = gameObject.transform.localScale;
                                goNewHull.transform.parent     = gameObject.transform;
                                MeshCollider meshCollider = goNewHull.AddComponent<MeshCollider>() as MeshCollider;

                                meshCollider.sharedMesh = null;
							    meshCollider.sharedMesh = hullMesh;
							    meshCollider.convex     = true;

                                nTotalTriangles += hullInfo.nTriangleCount;
                            }
                            else
                            {
                                if(bVerbose)
                                {
//                                    Debug.LogWarning("Error generating collider for " + gameObject.name + ": ComputeHull() returned 0 triangles. Approximating with another collider.");
                                }
                            }
                        }

                        if(info.nHullsOut == 0 && bVerbose)
                        {
//                            Debug.LogWarning("Error generating collider for " + gameObject.name + ": ComputeHull() returned 0 hulls. Approximating with another collider.");
                        }
                    }
                    else
                    {
                        if(bVerbose)
                        {
//                            Debug.LogWarning("Error generating collider for " + gameObject.name + ": ComputeHull() returned false. Approximating with another collider.");
                        }
                    }
                }
            }

            DllClose();
            return nTotalTriangles;
	    }