override public void Calculate(ref KrablMesh.MeshEdges mesh, KMProcessorProgram parentProgram = null)
    {
        base.Calculate(ref mesh);

        SubdivideQ           sub = new SubdivideQ();
        SubdivideQParameters par = new SubdivideQParameters();

        sub.progressDelegate = delegate(string text, float val) {
            ReportProgress(text, val);
        };

        par.trisToQuads         = trisToQuads;
        par.trisToQuadsMaxAngle = trisToQuadsMaxEdgeAngle;
        par.iterations          = iterations;
        par.recalculateNormals  = (normalMode == NormalMode.Recalculate);
        if (platformID != null)
        {
            for (int i = 0; i < iterationsOverridePlatform.Length; ++i)
            {
                if (platformID.Equals(iterationsOverridePlatform[i]))
                {
                    par.iterations = iterationsOverride[i];
                    break;
                }
            }
        }

        sub.Execute(ref mesh, par);
    }
    override public void Calculate(ref KrablMesh.MeshEdges mesh, KMProcessorProgram parentProgram = null)
    {
        base.Calculate(ref mesh);

        bool recalcNormals = false;

        KrablMesh.CreaseDetect.ClearAllCreases(mesh);

        if (creasesFromNormals)
        {
            KrablMesh.CreaseDetect.MarkCreasesFromFaceNormals(mesh, 1.0f);
            //		if (creaseStrength < 1.0f) recalcNormals = true;
        }
        else
        {
            recalcNormals = true;
        }

        if (creasesFromEdgeAngles)
        {
            KrablMesh.CreaseDetect.MarkCreasesFromEdgeAngles(mesh, minEdgeAngle, 1.0f);
            recalcNormals = true;
        }
        if (creasesFromMaterialSeams)
        {
            KrablMesh.CreaseDetect.MarkCreasesFromMaterialSeams(mesh, 1.0f);
            recalcNormals = true;
        }

        if (recalcNormals)
        {
            mesh.CalculateFaceVertexNormalsFromEdgeCreases();
        }
    }
        /// <summary>
        /// Searches through all edges of the mesh and compares the vertex normals on each face connected
        /// to an edge. If there is a difference in the vertex normals, the edge gets marked as crease.
        /// This method is automatically executed every time a Unity mesh is converted to a Krabl Mesh Library mesh.
        /// </summary>
        /// <param name='mesh'>
        /// The mesh to search.
        /// </param>
        /// <param name='creaseStrength'>
        /// The crease value to set the edges to. Currently only 1.0f has any effect.
        /// </param>
        public static void MarkCreasesFromFaceNormals(MeshEdges mesh, float creaseStrength = 1.0f)
        {
            mesh.CalculateEdgeLinkedFaces();
            int count = mesh.edgeCount();

            for (int edgeIndex = 0; edgeIndex < count; ++edgeIndex)
            {
                Edge edge = mesh.edges[edgeIndex];
                int  v1   = edge.v[0];
                int  v2   = edge.v[1];
                if (edge.linkedFaces.Count == 2)
                {
                    Face    fa  = mesh.faces[edge.linkedFaces[0]];
                    Face    fb  = mesh.faces[edge.linkedFaces[1]];
                    Vector3 n1a = fa.VertexNormalForVertexIndex(v1);
                    Vector3 n2a = fa.VertexNormalForVertexIndex(v2);
                    Vector3 n1b = fb.VertexNormalForVertexIndex(v1);
                    Vector3 n2b = fb.VertexNormalForVertexIndex(v2);
                    if (KrablMesh.UnityUtils.Vector3CompareWithTolerance(n1a, n1b, mesh.equalityTolerance) != 0 ||
                        KrablMesh.UnityUtils.Vector3CompareWithTolerance(n2a, n2b, mesh.equalityTolerance) != 0)
                    {
                        edge.crease = creaseStrength;
                    }
                }
            }
        }
Exemple #4
0
        public static void TriangulateWithEdges(MeshEdges mesh)
        {
            if (mesh.topology == MeshTopology.Triangles)
            {
                return;
            }

            int oldNumFaces = mesh.faceCount();

            Triangulate((BaseMesh)mesh);
            int newNumFaces = mesh.faceCount();

            // Iterate through the new faces
            for (int faceIndex = oldNumFaces; faceIndex < newNumFaces; ++faceIndex)
            {
                Face f = mesh.faces[faceIndex];
                Edge e = new Edge(f.v[0], f.v[1]);                 // the new edge is always 0->1 because triangulate is constructed to do that.
                mesh.AddEdge(e);
            }
            mesh.RegenerateVertexLinkedEdges();
            mesh.GenerateEdgeTopology();
            //mesh.GenerateEdgeList(); // not good! Looses edge information!
            // What was really needed is looking for the new edges created.. leave the old ones alone!
            //mesh.CalculateEdgeLinkedFaces();
        }
    override public void Calculate(ref KrablMesh.MeshEdges mesh, KMProcessorProgram parentProgram = null)
    {
        base.Calculate(ref mesh);

        if (materials == MaterialOption.Merge)
        {
            mesh.numMaterials = 1;
            int numFaces = mesh.faceCount();
            for (int i = 0; i < numFaces; ++i)
            {
                mesh.faces[i].material = 0;
            }
        }

        if (vertexColors == Option.Remove)
        {
            mesh.hasVertexColors = false;
        }

        if (uv1Option == Option.Remove)
        {
            mesh.hasUV1 = false;
        }

        if (uv2Option == Option.Remove)
        {
            mesh.hasUV2 = false;
        }

        /*if (skin == Option.Remove) {
         *      mesh.hasBoneWeights = false;
         *      mesh.bindposes = null;
         * }*/
    }
        /// <summary>
        /// Sets the crease value of all edges in the mesh to 0.
        /// </summary>
        /// <param name='mesh'>
        /// The mesh to process.
        /// </param>
        public static void ClearAllCreases(MeshEdges mesh)
        {
            int numEdges = mesh.edgeCount();

            for (int edgeIndex = 0; edgeIndex < numEdges; ++edgeIndex)
            {
                mesh.edges[edgeIndex].crease = 0.0f;
            }
        }
Exemple #7
0
 public void Cleanup()
 {
     _parameters      = null;
     progressDelegate = null;
     pdePerVertex     = null;
     heapNodes        = null;
     heap             = null;
     mesh             = null;
 }
 public UnityEngine.Mesh Process(UnityEngine.Mesh umesh, string platformID = null)
 {
     if (bypass == false)
     {
         KrablMesh.MeshEdges kmesh  = ProcessToKrablMesh(umesh, platformID);
         UnityEngine.Mesh    result = new UnityEngine.Mesh();
         KrablMesh.ImportExport.MeshEdgesToUnityMesh(kmesh, result);
         return(result);
     }
     return(umesh);
 }
    /// <summary>
    /// Change the normals of a mesh to produce a flat-shaded look. This will increase the vertex count as all vertices need to be split.
    /// </summary>
    /// <param name='unityMesh'>
    /// The mesh to flat shade.
    /// </param>

    public static void FlatShadeMesh(Mesh unityMesh)
    {
        KrablMesh.MeshEdges kmesh = new KrablMesh.MeshEdges();

        KrablMesh.ImportExport.UnityMeshToMeshEdges(unityMesh, kmesh);

        KrablMesh.CreaseDetect.MarkCreasesFromEdgeAngles(kmesh, 0.0f);
        kmesh.CalculateFaceVertexNormalsFromEdgeCreases();

        KrablMesh.ImportExport.MeshEdgesToUnityMesh(kmesh, unityMesh);
    }
    /// <summary>
    /// Change to normals of a mesh to produce a smooth-shaded look. This will reduce the vertex count and all mesh corners will just have one normal.
    /// </summary>
    /// <param name='unityMesh'>
    /// The mesh to smooth shade.
    /// </param>

    public static void SmoothShadeMesh(Mesh unityMesh)
    {
        KrablMesh.MeshEdges kmesh = new KrablMesh.MeshEdges();

        KrablMesh.ImportExport.UnityMeshToMeshEdges(unityMesh, kmesh);

        KrablMesh.CreaseDetect.ClearAllCreases(kmesh);
        kmesh.CalculateFaceVertexNormalsFromEdgeCreases();

        KrablMesh.ImportExport.MeshEdgesToUnityMesh(kmesh, unityMesh);
    }
        /// <summary>
        /// Searches the mesh for edges that are connected to faces of different materials (submeshes). These are
        /// marked as creases.
        /// </summary>
        /// <param name='mesh'>
        /// The mesh to search.
        /// </param>
        /// <param name='creaseStrength'>
        /// The crease value to set the edges to. Currently only 1.0f has any effect.
        /// </param>
        public static void MarkCreasesFromMaterialSeams(MeshEdges mesh, float creaseStrength = 1.0f)
        {
            int numEdges = mesh.edgeCount();

            for (int edgeIndex = 0; edgeIndex < numEdges; ++edgeIndex)
            {
                if (mesh.isEdgeMaterialSeam(edgeIndex))
                {
                    mesh.edges[edgeIndex].crease = creaseStrength;
                }
            }
        }
        /// <summary>
        /// Searches through all edges of the mesh and calculates the angle between the faces connected to the edge.
        /// The the angle is above the threshold, the edge is marked as a crease.
        /// </summary>
        /// <param name='mesh'>
        /// The mesh to search.
        /// </param>
        /// <param name='angleThreshold'>
        /// All edges with angles equal or larger than this are marked as creases.
        /// </param>
        /// <param name='creaseStrength'>
        /// The crease value to set the edges to. Currently only 1.0f has any effect.
        /// </param>
        public static void MarkCreasesFromEdgeAngles(MeshEdges mesh, float angleThreshold, float creaseStrength = 1.0f)
        {
            mesh.CalculateFaceNormals();
            int numEdges = mesh.edgeCount();

            for (int edgeIndex = 0; edgeIndex < numEdges; ++edgeIndex)
            {
                if (mesh.CalculateEdgeAngle(edgeIndex) >= angleThreshold)
                {
                    mesh.edges[edgeIndex].crease = creaseStrength;
                }
            }
        }
    /// <summary>
    /// Subdivides a mesh by applying a quads-based subdivision algorithm. Optionally, triangles are first merged to quads if possible to produce a better topology.
    /// For every iteration the face count of the mesh quadruples. The result mesh has quad topology.
    /// </summary>
    /// <param name='unityMesh'>
    /// The mesh to subdivide.
    /// </param>
    /// <param name='iterations'>
    /// The number of iterations the algorithm should perform. High numbers (>3) quickly lead to producing more triangles than
    /// unity can handle! (>65k).
    /// </param>
    /// <param name='trisToQuads'>
    /// Attempt to convert triangles to quads before the subdivision (highly recommended).
    /// </param>

    public static void SubdivideQuadsMesh(Mesh unityMesh, int iterations, bool trisToQuads = true)
    {
        KrablMesh.MeshEdges            kmesh   = new KrablMesh.MeshEdges();
        KrablMesh.SubdivideQ           sub     = new KrablMesh.SubdivideQ();
        KrablMesh.SubdivideQParameters subpars = new KrablMesh.SubdivideQParameters();

        KrablMesh.ImportExport.UnityMeshToMeshEdges(unityMesh, kmesh);
        subpars.trisToQuads = trisToQuads;
        subpars.iterations  = iterations;

        sub.Execute(ref kmesh, subpars);
        KrablMesh.ImportExport.MeshEdgesToUnityMesh(kmesh, unityMesh);
    }
Exemple #14
0
        // Simple implementation based on linkedEdges. It would be possible without edges, but this algo needs edges anyways
        bool _isVertexBorder(MeshEdges mesh, int vertIndex)
        {
            List <int> linkedEdges = mesh.linkedEdgesForVert(vertIndex);

            for (int i = 0; i < linkedEdges.Count; ++i)
            {
                int edgeIndex = linkedEdges[i];
                if (mesh.IsEdgeValid(edgeIndex) && mesh.IsEdgeBorder(edgeIndex))
                {
                    return(true);
                }
            }
            return(false);
        }
Exemple #15
0
        // the mesh needs to have its edge list and creases calculated
        public void InitializeCollapsing(MeshEdges _mesh, SimplifyParameters parameters)
        {
            mesh        = _mesh;
            _parameters = parameters;
            // Gain some time by avoiding unecessary calculations
            if (_mesh.hasBoneWeights == false)
            {
                parameters.boneWeightProtection = 0.0f;
            }
            if (_mesh.hasVertexColors == false)
            {
                parameters.vertexColorProtection = 0.0f;
            }

            _calculatePdePerVertex();
            // construct heap
            int numEdges = mesh.edgeCount();

            heapNodes = new HeapNode <CollapseInfo> [numEdges];
            heap      = new MinHeap <CollapseInfo>();
            int   progressCounter = kProgressGroups;
            float t = Time.realtimeSinceStartup;

            for (int i = 0; i < numEdges; ++i)
            {
                CollapseInfo pc = new CollapseInfo();
                _calculateEdgeCost(i, pc);
                heapNodes[i] = heap.Insert(new HeapNode <CollapseInfo>(pc.cost, pc));
                progressCounter--;
                if (progressCounter <= 0)
                {
                    progressCounter = kProgressGroups;
                    if (Time.realtimeSinceStartup - t > kProgressInterval && progressDelegate != null)
                    {
                        t = Time.realtimeSinceStartup;
                        progressDelegate("Initialize Edge " + i + "/" + numEdges, 0.1f * ((float)i) / ((float)numEdges));
                    }
                }
            }

            // shortcut for fastest calc
            noPenalties = (parameters.checkTopology == false &&
                           parameters.maxEdgesPerVertex == 0 &&
                           parameters.preventNonManifoldEdges == false &&
                           parameters.boneWeightProtection <= 0.0f &&
                           parameters.vertexColorProtection <= 0.0f);
            //sharpnessLimitSqr = parameters.minTriangleShape*parameters.minTriangleShape;
            //if (parameters.minTriangleShape < 0.0f) sharpnessLimitSqr = 0.0f;
        }
Exemple #16
0
        /// <summary>
        /// Perform quad-based mesh subdivision
        /// </summary>
        /// <param name='mesh'>
        /// A mesh (KrablMesh.MeshEdges) to subdivide. The mesh will be replaced by a new mesh structure.
        /// </param>
        /// <param name='parameters'>
        /// The parameters to use during the subdivison.
        /// </param>
        public void Execute(ref MeshEdges mesh, SubdivideQParameters parameters)
        {
            float progSteps = (float)parameters.iterations;

            if (parameters.trisToQuads)
            {
                progSteps += 1.0f;
            }
            if (parameters.recalculateNormals)
            {
                progSteps += 1.0f;
            }
            float progStep = (progSteps > 0.0f) ? (1.0f / progSteps) : 1.0f;
            float progress = 0.0f;

            smooth             = parameters.smooth;
            recalculateNormals = parameters.recalculateNormals;
            if (parameters.trisToQuads)
            {
                if (progressDelegate != null)
                {
                    progressDelegate("TrisToQuads", progress);
                    progress += progStep;
                }
                Ops.TrisToQuads(mesh, parameters.trisToQuadsMaxAngle);
            }
            for (int i = 0; i < parameters.iterations; ++i)
            {
                if (progressDelegate != null)
                {
                    progressDelegate("Iteration " + (i + 1), progress);
                    progress += progStep;
                }
                Subdivide(ref mesh);
            }
            if (recalculateNormals)
            {
                if (progressDelegate != null)
                {
                    progressDelegate("Recalculate Normals", progress);
                    progress += progStep;
                }
                mesh.CalculateFaceVertexNormalsFromEdgeCreases();
            }
        }
Exemple #17
0
    override public void Calculate(ref KrablMesh.MeshEdges mesh, KMProcessorProgram parentProgram = null)
    {
        base.Calculate(ref mesh);

        KrablMesh.Simplify           sim = new KrablMesh.Simplify();
        KrablMesh.SimplifyParameters par = new KrablMesh.SimplifyParameters();

        sim.progressDelegate = delegate(string text, float val) {
            ReportProgress(text, val);
        };

        //	par.maximumError = maximumError;
        par.targetFaceCount = targetTriangleCount;
        if (platformID != null)
        {
            for (int i = 0; i < ttcOverridePlatform.Length; ++i)
            {
                if (platformID.Equals(ttcOverridePlatform[i]))
                {
                    par.targetFaceCount = ttcOverrideTargetTriangleCount[i];
                    break;
                }
            }
        }

        par.recalculateVertexPositions = allowVertexReposition;
        par.preventNonManifoldEdges    = preventNonManifoldEdges;

        par.borderWeight       = borders;
        par.creaseWeight       = creases;
        par.uvSeamWeight       = uvSeams;
        par.uv2SeamWeight      = uv2Seams;
        par.materialSeamWeight = materialSeams;

        // par.minTriangleShape = minTriangleShape;

        par.boneWeightProtection  = boneWeightProtection;
        par.vertexColorProtection = vertexColorProtection;
        //	par.vertexNormalProtection  = vertexNormalProtection;

        sim.Execute(ref mesh, par);
    }
    /// <summary>
    /// Simplify a mesh by collapsing edges until the target face count is reached.
    /// </summary>
    /// <param name='unityMesh'>
    /// The mesh to simplify.
    /// </param>
    /// <param name='targetFaceCount'>
    /// The number of triangles to reduce the mesh to. If this is higher than the initial
    /// number of triangles, no processing will occur.
    /// </param>
    /// <param name='highQuality'>
    /// Use slower, but more precise calculations.
    /// </param>

    public static void SimplifyMesh(Mesh unityMesh, int targetFaceCount, bool highQuality = true)
    {
        KrablMesh.MeshEdges          kmesh   = new KrablMesh.MeshEdges();
        KrablMesh.Simplify           sim     = new KrablMesh.Simplify();
        KrablMesh.SimplifyParameters simpars = new KrablMesh.SimplifyParameters();

        KrablMesh.ImportExport.UnityMeshToMeshEdges(unityMesh, kmesh);
        simpars.targetFaceCount            = targetFaceCount;
        simpars.recalculateVertexPositions = highQuality;
        simpars.checkTopology     = !highQuality;
        simpars.maxEdgesPerVertex = highQuality ? 18 : 0;
        if (highQuality == false)
        {
            simpars.preventNonManifoldEdges = false;
            simpars.boneWeightProtection    = 0.0f;
            simpars.vertexColorProtection   = 0.0f;
        }

        sim.Execute(ref kmesh, simpars);
        KrablMesh.ImportExport.MeshEdgesToUnityMesh(kmesh, unityMesh);
    }
    public KrablMesh.MeshEdges ProcessToKrablMesh(UnityEngine.Mesh umesh, string platformID = null)
    {
        KrablMesh.MeshEdges kmesh = new KrablMesh.MeshEdges();
        inMeshDescription = MeshDescription(umesh);
        KrablMesh.ImportExport.UnityMeshToMeshEdges(umesh, kmesh, inputTolerance);

        if (bypass == false)
        {
            foreach (KrablMesh.Processor p in processors)
            {
                if (p.enabled == true)
                {
                    p.SetBuildPlatform(platformID);
                    //float t = Time.realtimeSinceStartup;
                    p.Calculate(ref kmesh, this);
                    // Debug.Log("Processor " + p.Name() + " took " + (Time.realtimeSinceStartup - t)*1000.0f + " ms.");
                }
            }
        }
        return(kmesh);
    }
Exemple #20
0
        /// <summary>
        /// Perform mesh simplification.
        /// </summary>
        /// <param name='mesh'>
        /// A mesh (KrablMesh.MeshEdges) to simplify. The mesh will be changed and might even be replaced by a new mesh structure.
        /// </param>
        /// <param name='parameters'>
        /// The parameters to use during the simplification.
        /// </param>
        public void Execute(ref MeshEdges mesh, SimplifyParameters parameters)
        {
            if (mesh.vertCount() == 0)
            {
                return;
            }

            if (mesh.topology != MeshTopology.Triangles)
            {
                Ops.TriangulateWithEdges(mesh);
            }

            if (progressDelegate != null)
            {
                progressDelegate("Initialize", 0.0f);
            }
            InitializeCollapsing(mesh, parameters);
            if (parameters.edgesToCollapse > 0)
            {
                Collapse(parameters.edgesToCollapse);
            }
            else if (parameters.targetFaceCount > 0)
            {
                int   totalFacesToRemove = mesh.numValidFaces - parameters.targetFaceCount;
                int   progressCounter    = 0;
                float t = Time.realtimeSinceStartup + kProgressInterval;
                while (mesh.numValidFaces > parameters.targetFaceCount)
                {
                    Collapse(1);
                    progressCounter--;
                    if (progressCounter <= 0)
                    {
                        progressCounter = kProgressGroups;
                        if (Time.realtimeSinceStartup - t > kProgressInterval && progressDelegate != null)
                        {
                            t = Time.realtimeSinceStartup;
                            int facesRemoved = totalFacesToRemove - (mesh.numValidFaces - parameters.targetFaceCount);
                            progressDelegate("Mesh Faces " + mesh.numValidFaces + "->" + parameters.targetFaceCount, 0.1f + 0.9f * ((float)facesRemoved) / ((float)totalFacesToRemove));
                        }
                    }
                }
            }
            else if (parameters.maximumError > 0)
            {
                // Determine size of mesh to scale errors
                meshSize = _determineMeshSize(mesh);
                int   totalFacesToRemove = mesh.numValidFaces;
                float t             = Time.realtimeSinceStartup + kProgressInterval;
                float costThreshold = meshSize * parameters.maximumError * 0.001f;
                costThreshold *= costThreshold;
                int progressCounter = 0;
                while (true)
                {
                    int num = Collapse(1, costThreshold);
                    if (num == 0)
                    {
                        break;
                    }
                    progressCounter--;
                    if (progressCounter <= 0)
                    {
                        progressCounter = kProgressGroups;
                        if (Time.realtimeSinceStartup - t > kProgressInterval && progressDelegate != null)
                        {
                            t = Time.realtimeSinceStartup;
                            int facesRemoved = totalFacesToRemove - (mesh.numValidFaces - parameters.targetFaceCount);
                            progressDelegate("Mesh Faces " + mesh.numValidFaces + "->" + parameters.targetFaceCount, 0.1f + 0.9f * ((float)facesRemoved) / ((float)totalFacesToRemove));                         // TODO: do this better
                        }
                    }
                }
            }
            //Debugging.CheckMeshIntegrity(mesh);
            mesh.RebuildMesh();

            /*float minShape = Debugging.CalculateMinTriangleShape(mesh);
             * Debug.LogError("MIN TRIANGLE SHAPE" + Mathf.Sqrt(minShape) + " param " + Mathf.Sqrt(sharpnessLimitSqr));
             */
            Cleanup();
        }
Exemple #21
0
        public static bool CheckMeshIntegrity(MeshEdges mesh)
        {
            // Vertex linked faces
            int numVerts = mesh.vertCount();
            int numFaces = mesh.faceCount();
            int numEdges = mesh.edgeCount();

            List <int>[] mVertexLinkedFaces = new List <int> [numVerts];
            for (int i = 0; i < numVerts; ++i)
            {
                mVertexLinkedFaces[i] = new List <int>();
            }
            for (int i = 0; i < numFaces; ++i)
            {
                Face f = mesh.faces[i];
                if (f.valid)
                {
                    for (int j = 0; j < f.cornerCount; ++j)
                    {
                        int vertIndex = f.v[j];
                        if (mesh.IsVertexValid(vertIndex))
                        {
                            mVertexLinkedFaces[vertIndex].Add(i);
                        }
                    }
                }
            }
            for (int i = 0; i < numVerts; ++i)
            {
                if (mesh.IsVertexValid(i))
                {
                    IndexList test = new IndexList(4);
                    for (int j = 0; j < mesh.vertices[i].linkedFaces.Count; ++j)
                    {
                        if (mesh.faces[mesh.vertices[i].linkedFaces[j]].valid)
                        {
                            test.Add(mesh.vertices[i].linkedFaces[j]);
                        }
                    }

                    /*if (_areIntListsTheSame(mesh.vertices[i].linkedFaces, mVertexLinkedFaces[i]) == false) {
                     *      Debug.LogError("INVALID MESH vertexLinkedFaces not correct for vertex " + i);
                     *      return false;
                     * }*/
                }
            }

            // Vertex linked edges
            for (int i = 0; i < numVerts; ++i)
            {
                if (mesh.IsVertexValid(i))
                {
                    List <int> li1 = new List <int>();
                    mesh.CollectVerticesAroundVertex(i, ref li1);
                    List <int> li2 = new List <int>();
                    List <int> le  = mesh.linkedEdgesForVert(i);
                    for (int j = 0; j < le.Count; ++j)
                    {
                        if (mesh.IsEdgeValid(le[j]))
                        {
                            li2.Add(mesh.edges[le[j]].OtherVertex(i));
                        }
                    }
                    if (_areIntListsTheSame(li1, li2) == false)
                    {
                        Debug.LogError("INVALID MESH vertexLinkedEdges not correct for vertex" + i);
                        return(false);
                    }
                }
            }

            // Edge linked faces
            for (int i = 0; i < numEdges; ++i)
            {
                if (mesh.IsEdgeValid(i))
                {
                    IndexList test = new IndexList(18);
                    mesh.CollectVertexPairFaces(mesh.edges[i], test);

                    /*	if (_areIntListsTheSame(test, mesh.edges[i).linkedFaces) == false) {
                     *              Debug.LogError("INVALID MESH edgeLinkedFaces not correct for edge" + i);
                     *              return false;
                     *      }*/
                }
            }

            Debug.Log("Mesh integrity is good.");
            return(true);
        }
Exemple #22
0
        /// <summary>
        /// Copy mesh data from a KrablMesh meshEdges to a Unity Mesh.
        /// </summary>
        /// <param name='meshEdges'>
        /// The input mesh.
        /// </param>
        /// <param name='unityMesh'>
        /// The output Unity Mesh. Any data it contains will be overwritten.
        /// </param>
        public static void MeshEdgesToUnityMesh(KrablMesh.MeshEdges meshEdges, UnityEngine.Mesh unityMesh)
        {
            meshEdges.InvalidateDegenerateFaces();
            //	Ops.TriangulateWithEdges(meshEdges);
            int numFaces = meshEdges.faceCount();

            List <ExportVertex> exVerts = new List <ExportVertex>(numFaces * 3);

            List <Vector3> verts = new List <Vector3>();

            List <int>[] indices     = new List <int> [meshEdges.numMaterials];
            List <int>   vertexTable = new List <int>();

            // Create a list of all vertices based on face corners (= lots of duplicates)
            for (int material = 0; material < meshEdges.numMaterials; ++material)
            {
                indices[material] = new List <int>();
                for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex)
                {
                    Face f = meshEdges.faces[faceIndex];
                    if (f.valid && f.material == material)
                    {
                        int cornerCount = f.cornerCount;
                        for (int cornerIndex = 0; cornerIndex < cornerCount; ++cornerIndex)
                        {
                            ExportVertex ev = new ExportVertex();
                            ev.vertIndex   = f.v[cornerIndex];
                            ev.cornerCount = cornerCount;
                            ev.material    = material;
                            ev.coords      = meshEdges.vertices[f.v[cornerIndex]].coords;
                            ev.normal      = f.vertexNormal[cornerIndex];
                            ev.uv1         = f.uv1[cornerIndex];
                            ev.uv2         = f.uv2[cornerIndex];

                            vertexTable.Add(exVerts.Count);
                            exVerts.Add(ev);
                        }
                    }
                }
            }

            vertexTable.Sort(delegate(int a, int b) {
                return(ExportVertex.CompareEV(exVerts[a], exVerts[b]));
            });

            // Create index list to collapse list to the unique verts added to the final mesh
            // compile unique mesh arrays
            List <Vector3>    normals     = new List <Vector3>();
            List <Vector2>    uv1         = new List <Vector2>();
            List <Vector2>    uv2         = new List <Vector2>();
            List <Color>      vertColors  = new List <Color>();
            List <BoneWeight> boneWeights = new List <BoneWeight>();

            int[] uniqueTable = new int[exVerts.Count];
            int   numUnique   = 0;

            for (int i = 0; i < exVerts.Count; ++i)
            {
                int exIndex = vertexTable[i];
                if (i == 0 || ExportVertex.CompareEV(exVerts[vertexTable[i - 1]], exVerts[exIndex]) != 0)
                {
                    verts.Add(exVerts[exIndex].coords);
                    normals.Add(exVerts[exIndex].normal);
                    uv1.Add(exVerts[exIndex].uv1);
                    uv2.Add(exVerts[exIndex].uv2);

                    Vertex v = meshEdges.vertices[exVerts[exIndex].vertIndex];
                    vertColors.Add(v.color);
                    boneWeights.Add(v.boneWeight);
                    numUnique++;
                }
                uniqueTable[exIndex] = numUnique - 1;
            }
            //	Debug.Log("Num exVerts " + exVerts.Length + " num collapsed " + numUnique + " vertsCount " + verts.Count);
#if false                                                     // Quad topology seams to be broken on windows directx! Disabled it for now.
            if (meshEdges.topology == MeshTopology.Triangles) // quads/tris only
            {
                for (int i = 0; i < exVerts.Count; i += 3)
                {
                    int mat = exVerts[i].material;
                    indices[mat].Add(uniqueTable[i]);
                    indices[mat].Add(uniqueTable[i + 1]);
                    indices[mat].Add(uniqueTable[i + 2]);
                }
            }
            else if (meshEdges.topology == MeshTopology.Quads)
            {
                for (int i = 0; i < exVerts.Count; i += 4)
                {
                    int mat = exVerts[i].material;
                    indices[mat].Add(uniqueTable[i]);
                    indices[mat].Add(uniqueTable[i + 1]);
                    indices[mat].Add(uniqueTable[i + 2]);
                    indices[mat].Add(uniqueTable[i + 3]);
                }
            }
            else
#endif
            {
                // Mixed tris/quads need to split quads
                int cornerCount, mat;
                int i0, i1, i2, i3;
                for (i0 = 0; i0 < exVerts.Count;)
                {
                    i1          = i0 + 1;
                    i2          = i0 + 2;
                    cornerCount = exVerts[i0].cornerCount;
                    mat         = exVerts[i0].material;
                    if (cornerCount == 3)
                    {
                        indices[mat].Add(uniqueTable[i0]);
                        indices[mat].Add(uniqueTable[i1]);
                        indices[mat].Add(uniqueTable[i2]);
                        i0 += 3;
                    }
                    else                         // Quad!
                    {
                        i3 = i0 + 3;
                        Vector3 diag02 = exVerts[i0].coords - exVerts[i2].coords;
                        Vector3 diag13 = exVerts[i1].coords - exVerts[i3].coords;

                        if (diag02.sqrMagnitude > diag13.sqrMagnitude)
                        {
                            // If 0-2 if shorter than 1-3
                            indices[mat].Add(uniqueTable[i0]);
                            indices[mat].Add(uniqueTable[i1]);
                            indices[mat].Add(uniqueTable[i2]);

                            indices[mat].Add(uniqueTable[i0]);
                            indices[mat].Add(uniqueTable[i2]);
                            indices[mat].Add(uniqueTable[i3]);
                        }
                        else
                        {
                            indices[mat].Add(uniqueTable[i0]);
                            indices[mat].Add(uniqueTable[i1]);
                            indices[mat].Add(uniqueTable[i3]);

                            indices[mat].Add(uniqueTable[i1]);
                            indices[mat].Add(uniqueTable[i2]);
                            indices[mat].Add(uniqueTable[i3]);
                        }
                        i0 += 4;
                    }
                }
            }

            unityMesh.Clear(false);
            unityMesh.name = "KMesh";

            if (verts.Count >= 65536 || exVerts.Count >= 65536 * 3)
            {
                Debug.Log("Cannot create Unity mesh from KrablMesh.MeshEdges. " +
                          "The mesh is too large (>65k). " +
                          "Vertices: " + verts.Count + " Triangles: " + exVerts.Count / 3);
                return;
            }

            unityMesh.subMeshCount = meshEdges.numMaterials;
            unityMesh.vertices     = verts.ToArray();
            unityMesh.normals      = normals.ToArray();
            if (meshEdges.hasVertexColors)
            {
                unityMesh.colors = vertColors.ToArray();
            }
            if (meshEdges.hasUV1)
            {
                unityMesh.uv = uv1.ToArray();
            }
            if (meshEdges.hasUV2)
            {
                unityMesh.uv2 = uv2.ToArray();
            }
            if (meshEdges.hasBoneWeights)
            {
                unityMesh.bindposes   = meshEdges.bindposes;
                unityMesh.boneWeights = boneWeights.ToArray();
            }
#if false
            if (meshEdges.topology == MeshTopology.Quads)
            {
                for (int mat = 0; mat < meshEdges.numMaterials; ++mat)
                {
                    unityMesh.SetIndices(indices[mat].ToArray(), UnityEngine.MeshTopology.Quads, mat);
                }
            }
            else
#endif
            {
                for (int mat = 0; mat < meshEdges.numMaterials; ++mat)
                {
                    unityMesh.SetTriangles(indices[mat].ToArray(), mat);
                }
            }
            if (meshEdges.hasUV1 && meshEdges.calculateTangents)
            {
                _calculateMeshTangents(unityMesh);
            }
        }
Exemple #23
0
        // TrisToQuads. Needs mesh with edgelist
        /// <summary>
        /// Joins neighbour triangles to quads in a mesh by dissolving selected edges.
        /// This method needs the mesh to have its edges calculated. The edges are sorted
        /// by their angles and dissolved in order until the maximum edge angle is reached.
        /// Special edges such as uv borders or material seams are not dissolved and concave quads
        /// are avoided. This method is used by the quad-based subdivision algorithm as it works
        /// much better with quads.
        /// </summary>
        /// <param name='mesh'>
        /// The mesh to process.
        /// </param>
        /// <param name='maximumEdgeAngle'>
        /// The maximum angle between two triangles to be joined to a (non-planar) quad.
        /// </param>
        public static void TrisToQuads(MeshEdges mesh, float maximumEdgeAngle)
        {
            if (mesh.topology != MeshTopology.Triangles)
            {
                return;
            }
            int i, j;

            mesh.topology = MeshTopology.Mixed;             // Most likely we'll end up with a mixed topology as some triangles will be left.
            mesh.CalculateFaceNormals();
            mesh.CalculateEdgeLinkedFaces();
            // Calculate the edge angles and compile list of 2-face edges
            int         numEdges   = mesh.edgeCount();
            List <Edge> inneredges = new List <Edge>();

            for (i = 0; i < numEdges; ++i)
            {
                Edge e = mesh.edges[i]
                ;
                if (e.linkedFaces.Count == 2 && mesh.CanEdgeBeDissolved(i))
                {
                    e.mark  = i;                    // Save the index!
                    e.angle = mesh.CalculateEdgeAngle(i);
                    if (e.angle < maximumEdgeAngle)
                    {
                        inneredges.Add(e);
                    }
                }
            }
            // Sort by angle
            inneredges.Sort(delegate(Edge a, Edge b) { return(a.angle.CompareTo(b.angle)); });

            int iecount = inneredges.Count;

            //		Debug.Log("Number of inneredges " + iecount);
            Vector3[] qVec = new Vector3[5];
            for (i = 0; i < iecount; ++i)
            {
                Edge e = inneredges[i];

                Face f1 = mesh.faces[e.linkedFaces[0]];
                Face f2 = mesh.faces[e.linkedFaces[1]];

                // check if edge is between two triangles
                if (f1.valid && f2.valid && (f1.cornerCount == 3) && (f2.cornerCount == 3))
                {
                    // Make sure this doesn't lead to a concave quad
                    Vector3 newNormal = f1.normal + f2.normal;
                    //newNormal.Normalize();
                    // Collect all vertex coordinates
                    qVec[0] = mesh.vertices[e.v[0]].coords;
                    qVec[2] = mesh.vertices[e.v[1]].coords;
                    for (j = 0; j < 3; ++j)
                    {
                        if (e.ContainsVertex(f1.v[j]) == false)
                        {
                            qVec[1] = mesh.vertices[f1.v[j]].coords;
                            break;
                        }
                    }
                    for (j = 0; j < 3; ++j)
                    {
                        if (e.ContainsVertex(f2.v[j]) == false)
                        {
                            qVec[3] = mesh.vertices[f2.v[j]].coords;
                            break;
                        }
                    }
                    // Flip order if it doesn't conform to f1
                    if (f1.VerticesInOrder(e.v[0], e.v[1]) == true)
                    {
                        Vector3 temp = qVec[1]; qVec[1] = qVec[3]; qVec[3] = temp;
                    }
                    // calculate edge vectors
                    qVec[4] = qVec[0];
                    for (j = 0; j < 4; ++j)
                    {
                        qVec[j] -= qVec[j + 1];
                    }
                    qVec[4] = qVec[0];

                    bool convex = true;
                    for (j = 0; j < 4; ++j)
                    {
                        Vector3 localN = Vector3.Cross(qVec[j], qVec[j + 1]);
                        //localN.Normalize();
                        float nAngleCos = Vector3.Dot(newNormal, localN);
                        //Debug.Log("Angle " + nAngleCod);
                        if (nAngleCos <= 0.0f)
                        {
                            convex = false;
                            break;
                        }
                    }

                    if (convex)
                    {
                        //				Debug.Log("Dissolving edge");
                        mesh.DissolveEdgeTriangles(e.mark);
                    }
                    else
                    {
                        //		Debug.Log("not dissolving edge -> concave quad");
                    }
                }
            }

            // There are now invalid faces and edges
            mesh.RebuildMesh();
            mesh.GenerateEdgeTopology();
        }
Exemple #24
0
        /// <summary>
        /// Copies a Unity Mesh to a KrablMesh.MeshEdges.
        /// </summary>
        /// <param name='unityMesh'>
        /// The Unity Mesh to use as input.
        /// </param>
        /// <param name='meshEdges'>
        /// The KrablMesh.meshEdges to fill with the data from the input mesh. Needs to be empty.
        /// </param>
        /// <param name='tolerance'>
        /// The maximum difference between two values (vertex coordinates, normal coordinates) to treat as begin equal.
        /// Some modelling software outputs float values that are only almost the same when they should be the same.
        /// In this case using a tolerance of about 1e-5f can fix problems.
        /// </param>
        public static void UnityMeshToMeshEdges(UnityEngine.Mesh unityMesh, KrablMesh.MeshEdges meshEdges, float tolerance = 0.0f)
        {
            Vector3[]    verts       = unityMesh.vertices;
            Vector3[]    normals     = unityMesh.normals;
            Color[]      vertColors  = unityMesh.colors;
            BoneWeight[] boneWeights = unityMesh.boneWeights;
            Vector2[]    uv1         = unityMesh.uv;
            Vector2[]    uv2         = unityMesh.uv2;

            meshEdges.Clear();
            meshEdges.numMaterials      = unityMesh.subMeshCount;
            meshEdges.equalityTolerance = tolerance;

            int numVerts = verts.Length;

            meshEdges.hasVertexColors = (vertColors.Length == numVerts);
            meshEdges.bindposes       = unityMesh.bindposes;
            meshEdges.hasBoneWeights  = (meshEdges.bindposes != null && boneWeights.Length == numVerts);
            meshEdges.hasUV1          = (uv1.Length == numVerts);
            meshEdges.hasUV2          = (uv2.Length == numVerts);

            int i;

            for (i = 0; i < numVerts; ++i)
            {
                meshEdges.AddVertex(verts[i]);
            }
            if (meshEdges.hasVertexColors)
            {
                for (i = 0; i < numVerts; ++i)
                {
                    meshEdges.vertices[i].color = vertColors[i];
                }
            }
            if (meshEdges.hasBoneWeights)
            {
                for (i = 0; i < numVerts; ++i)
                {
                    meshEdges.vertices[i].boneWeight = boneWeights[i];
                }
            }

            // Figure out if this is a unity quad mesh.
            // theoretically this could be different per material
            bool quad = true;

            for (int m = 0; m < meshEdges.numMaterials; ++m)
            {
                if (unityMesh.GetTopology(m) != UnityEngine.MeshTopology.Quads)
                {
                    quad = false;
                    break;
                }
            }

            int v0, v1, v2, v3;

            for (int m = 0; m < meshEdges.numMaterials; ++m)
            {
                if (quad)
                {
                    int[] indices = unityMesh.GetIndices(m);
                    int   num     = indices.Length;
                    for (i = 0; i < num;)
                    {
                        v0 = indices[i++]; v1 = indices[i++]; v2 = indices[i++]; v3 = indices[i++];
                        Face f = new Face(v0, v1, v2, v3);
                        meshEdges.AddFace(f);
                        f.vertexNormal[0] = normals[v0]; f.vertexNormal[1] = normals[v1]; f.vertexNormal[2] = normals[v2]; f.vertexNormal[3] = normals[v3];
                        if (meshEdges.hasUV1)
                        {
                            f.uv1[0] = uv1[v0]; f.uv1[1] = uv1[v1]; f.uv1[2] = uv1[v2]; f.uv1[3] = uv1[v3];
                        }
                        if (meshEdges.hasUV2)
                        {
                            f.uv2[0] = uv2[v0]; f.uv2[1] = uv2[v1]; f.uv2[2] = uv2[v2]; f.uv2[3] = uv2[v3];
                        }
                        f.material = m;
                    }
                }
                else
                {
                    int[] tris = unityMesh.GetTriangles(m);
                    int   num  = tris.Length;
                    for (i = 0; i < num;)
                    {
                        v0 = tris[i++]; v1 = tris[i++]; v2 = tris[i++];
                        Face f = new Face(v0, v1, v2);
                        meshEdges.AddFace(f);
                        f.vertexNormal[0] = normals[v0]; f.vertexNormal[1] = normals[v1]; f.vertexNormal[2] = normals[v2];
                        if (meshEdges.hasUV1)
                        {
                            f.uv1[0] = uv1[v0]; f.uv1[1] = uv1[v1]; f.uv1[2] = uv1[v2];
                        }
                        if (meshEdges.hasUV2)
                        {
                            f.uv2[0] = uv2[v0]; f.uv2[1] = uv2[v1]; f.uv2[2] = uv2[v2];
                        }
                        f.material = m;
                    }
                }
            }

            KrablMesh.Ops.RemoveDoubleVertices(meshEdges);
            meshEdges.GenerateEdgeList();
            meshEdges.CalculateEdgeLinkedFaces();
            meshEdges.topology = quad ? MeshTopology.Quads : MeshTopology.Triangles;
            KrablMesh.CreaseDetect.MarkCreasesFromFaceNormals(meshEdges);
        }
Exemple #25
0
        public void Subdivide(ref MeshEdges mesh)
        {
            int i, j;
            int numVerts = mesh.vertCount();
            int numFaces = mesh.faceCount();
            int numEdges = mesh.edgeCount();

            mesh.CalculateEdgeLinkedFaces();

            _calculateVertexPositions(mesh);

            // TODO:don't generate a new mesh... just add the verts to the old mesh = faster and uses less memory
            MeshEdges newMesh    = new MeshEdges();
            int       faceOffset = numVerts;
            int       edgeOffset = numVerts + numFaces;

            float[] edgeRatio = new float[numEdges];

            // Add vertices to new mesh, precalculate stuff
            for (i = 0; i < numVerts; ++i)
            {
                newMesh.AddVertex(vertPoints[i]);
            }
            for (i = 0; i < numFaces; ++i)
            {
                newMesh.AddVertex(facePoints[i]);
            }
            for (i = 0; i < numEdges; ++i)
            {
                int    vertexIndex = newMesh.AddVertex(edgePoints[i]);
                Vertex nv          = newMesh.vertices[vertexIndex];
                Vertex ov0         = mesh.vertices[mesh.edges[i].v[0]];
                Vertex ov1         = mesh.vertices[mesh.edges[i].v[1]];
                edgeRatio[i] = KrablMesh.UnityUtils.ProjectedRatioOfPointOnVector(nv.coords, ov0.coords, ov1.coords);
            }

            if (mesh.hasBoneWeights)
            {
                for (i = 0; i < numVerts; ++i)
                {
                    newMesh.vertices[i].boneWeight = mesh.vertices[i].boneWeight;
                }
                for (i = 0; i < numEdges; ++i)
                {
                    int[] vi = mesh.edges[i].v;
                    newMesh.vertices[edgeOffset + i].boneWeight = KrablMesh.UnityUtils.BoneWeightLerp(
                        mesh.vertices[vi[0]].boneWeight,
                        mesh.vertices[vi[1]].boneWeight,
                        edgeRatio[i]);
                }
                for (i = 0; i < numFaces; ++i)
                {
                    newMesh.vertices[faceOffset + i].boneWeight = mesh.CalculateFaceCenterBoneWeight(i);
                }
            }

            if (mesh.hasVertexColors)
            {
                for (i = 0; i < numVerts; ++i)
                {
                    newMesh.vertices[i].color = mesh.vertices[i].color;
                }
                for (i = 0; i < numEdges; ++i)
                {
                    int[] vi = mesh.edges[i].v;
                    newMesh.vertices[edgeOffset + i].color = Color.Lerp(
                        mesh.vertices[vi[0]].color,
                        mesh.vertices[vi[1]].color,
                        edgeRatio[i]);
                }
                for (i = 0; i < numFaces; ++i)
                {
                    newMesh.vertices[faceOffset + i].color = mesh.CalculateFaceCenterColor(i);
                }
            }

            // Create the faces
            Face nf, of;
            int  g, h;
            int  a, b, c, d;

            for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex)
            {
                of = mesh.faces[faceIndex];
                if (of.valid)
                {
                    h = of.cornerCount - 1;                     // scan through with indices g, h, i
                    g = of.cornerCount - 2;
                    Vector2 centerUV1          = mesh.CalculateFaceCenterUV1(faceIndex);
                    Vector2 centerUV2          = mesh.CalculateFaceCenterUV2(faceIndex);
                    Vector3 centerVertexNormal = mesh.CalculateFaceCenterVertexNormal(faceIndex);
                    for (i = 0; i < of.cornerCount; ++i)
                    {
                        int edgeIndex0 = mesh.EdgeIndexForVertices(of.v[h], of.v[i]);
                        if (edgeIndex0 < 0)
                        {
                            continue;
                        }
                        float ratio0 = edgeRatio[edgeIndex0];
                        if (mesh.edges[edgeIndex0].v[0] == of.v[h])
                        {
                            a = h; b = i;                             // interpolation indexes. 1- ratio gives inaccurate results (floating point problems)
                        }
                        else
                        {
                            a = i; b = h;
                        }

                        int edgeIndex1 = mesh.EdgeIndexForVertices(of.v[g], of.v[h]);
                        if (edgeIndex1 < 0)
                        {
                            continue;
                        }
                        float ratio1 = edgeRatio[edgeIndex1];
                        if (mesh.edges[edgeIndex1].v[0] == of.v[g])
                        {
                            c = g; d = h;
                        }
                        else
                        {
                            c = h; d = g;
                        }

                        nf = new Face(
                            of.v[h],                             // corner point
                            edgeOffset + edgeIndex0,
                            faceOffset + faceIndex,              // center point
                            edgeOffset + edgeIndex1
                            );
                        nf.uv1[0] = of.uv1[h];
                        nf.uv1[1] = Vector2.Lerp(of.uv1[a], of.uv1[b], ratio0);
                        nf.uv1[2] = centerUV1;
                        nf.uv1[3] = Vector2.Lerp(of.uv1[c], of.uv1[d], ratio1);

                        if (mesh.hasUV2)
                        {
                            nf.uv2[0] = of.uv2[h];
                            nf.uv2[1] = Vector2.Lerp(of.uv2[a], of.uv2[b], ratio0);
                            nf.uv2[2] = centerUV2;
                            nf.uv2[3] = Vector2.Lerp(of.uv2[c], of.uv2[d], ratio1);
                        }

                        if (!recalculateNormals)
                        {
                            nf.vertexNormal[0] = of.vertexNormal[h];
                            nf.vertexNormal[1] = Vector3.Lerp(of.vertexNormal[a], of.vertexNormal[b], ratio0);
                            nf.vertexNormal[2] = centerVertexNormal;
                            nf.vertexNormal[3] = Vector3.Lerp(of.vertexNormal[c], of.vertexNormal[d], ratio1);
                        }

                        nf.material = of.material;

                        newMesh.AddFace(nf);
                        g = h;
                        h = i;
                    }
                }
            }

            newMesh.hasUV1          = mesh.hasUV1;
            newMesh.hasUV2          = mesh.hasUV2;
            newMesh.hasBoneWeights  = mesh.hasBoneWeights;
            newMesh.bindposes       = mesh.bindposes;
            newMesh.numMaterials    = mesh.numMaterials;
            newMesh.hasVertexColors = mesh.hasVertexColors;

            newMesh.topology = MeshTopology.Quads;
            newMesh.GenerateEdgeList();
            newMesh.GenerateEdgeTopology();
            // Need to copy edge information from the original mesh to the new mesh
            // Every edge of the original mesh now has two parts

            int edgePointIndex;

            for (i = 0; i < numEdges; ++i)
            {
                Edge e = mesh.edges[i];
                edgePointIndex = edgeOffset + i;                 // as newmesh was just constructed, we know the correct vertex index of the edge center point!
                for (j = 0; j < 2; ++j)
                {
                    int eindex = newMesh.EdgeIndexForVertices(e.v[j], edgePointIndex);

                    // Copy attributes (just crease for now)
                    newMesh.edges[eindex].crease = e.crease;
                }
            }
            mesh = newMesh;
        }
Exemple #26
0
        void _calculateVertexPositions(MeshEdges mesh)
        {
            int numVerts = mesh.vertCount();
            int numFaces = mesh.faceCount();
            int numEdges = mesh.edgeCount();

            vertPoints = new Vector3[numVerts];
            facePoints = new Vector3[numFaces];
            edgePoints = new Vector3[numEdges];

            // In any case the new face points are the center of the faces
            for (int i = 0; i < numFaces; ++i)
            {
                facePoints[i] = mesh.CalculateFaceCenter(i);
            }

            if (smooth)
            {
                // First count the number of creases connected to each vertex
                int[] vertexNumCreases = new int[numVerts];
                for (int i = 0; i < numVerts; ++i)
                {
                    List <int> linkedEdges = mesh.linkedEdgesForVert(i);
                    for (int j = 0; j < linkedEdges.Count; ++j)
                    {
                        int edgeIndex = linkedEdges[j];
                        if (mesh.IsEdgeValid(edgeIndex) && mesh.edges[edgeIndex].crease > 0.0)
                        {
                            vertexNumCreases[i]++;
                        }
                    }
                }

                // Edge is the average of the two ends and the connected face centers
                for (int i = 0; i < numEdges; ++i)
                {
                    Edge      e           = mesh.edges[i];
                    IndexList linkedFaces = e.linkedFaces;
                    edgePoints[i] = mesh.CalculateVertexPairCenter(e);

                    // If an edge connects two verts that do not move, use the center to prevent overlaps
                    //bool betweenNonMovableVertices = (vertexNumCreases[e.v[0]] > 2 && vertexNumCreases[e.v[1]] > 2);
                    //if (betweenNonMovableVertices) Debug.Log("Between NONmovable verts");
                    if (/*betweenNonMovableVertices == false &&*/ e.crease == 0.0f && linkedFaces.Count >= 2)
                    {
                        // creases and borders stay at edge centers
                        // other edges use the edge center + the center of all attached face centers
                        Vector3 faceCenterCenter = facePoints[linkedFaces[0]];
                        int     numLinked        = e.linkedFaces.Count;
                        for (int j = 1; j < numLinked; ++j)
                        {
                            faceCenterCenter += facePoints[linkedFaces[j]];
                        }
                        edgePoints[i] = 0.5f * (edgePoints[i] + faceCenterCenter * (1.0f / ((float)numLinked)));
                    }
                }
                // Vert
                for (int i = 0; i < numVerts; ++i)
                {
                    Vector3    oldPosition = mesh.vertices[i].coords;
                    List <int> linkedEdges = mesh.linkedEdgesForVert(i);
                    if (_isVertexBorder(mesh, i) == false)
                    {
                        // First deal with edges. the number of creases needs to be known!


                        Vector3 edgesCenter  = Vector3.zero;
                        float   numCreases   = 0.0f;
                        Vector3 creaseCenter = Vector3.zero;
                        float   nEdges       = 0.0f;
                        for (int j = 0; j < linkedEdges.Count; ++j)
                        {
                            int edgeIndex = linkedEdges[j];
                            if (mesh.IsEdgeValid(edgeIndex))
                            {
                                Edge    e      = mesh.edges[edgeIndex];
                                Vector3 center = mesh.CalculateVertexPairCenter(e);
                                if (e.crease > 0.0f)
                                {
                                    numCreases   += 1.0f;
                                    creaseCenter += center;
                                }
                                nEdges      += 1.0f;
                                edgesCenter += center;
                            }
                        }
                        edgesCenter *= 1.0f / nEdges;

                        // For points without crease edges or just one -> do nothing
                        if (numCreases == 2.0f)
                        {
                            // like a border connection
                            vertPoints[i] = 0.5f * oldPosition + creaseCenter * (0.5f / numCreases);
                        }
                        else if (numCreases > 2.0f)
                        {
                            // A sharp corner
                            vertPoints[i] = oldPosition;
                        }
                        else
                        {
                            // Full formula including faces center which needs to be calculated
                            IndexList linkedFaces = mesh.vertices[i].linkedFaces;
                            Vector3   facesCenter = Vector3.zero;
                            float     n           = 0.0f;
                            for (int j = 0; j < linkedFaces.Count; ++j)
                            {
                                int faceIndex = linkedFaces[j];
                                if (mesh.faces[faceIndex].valid)
                                {
                                    facesCenter += facePoints[faceIndex];
                                    n           += 1.0f;
                                }
                            }
                            float invN = 1.0f / n;
                            vertPoints[i] = (facesCenter * invN + 2.0f * edgesCenter + (n - 3.0f) * oldPosition) * invN;                     // useless for 2 creases!!!
                        }
                    }
                    else
                    {
                        // Border Vertex. get center of all connected border centers.
                        if (vertexNumCreases[i] > 2)
                        {
                            vertPoints[i] = oldPosition;
                        }
                        else
                        {
                            float   nBorders     = 0.0f;
                            Vector3 borderCenter = Vector3.zero;
                            for (int j = 0; j < linkedEdges.Count; ++j)
                            {
                                int edgeIndex = linkedEdges[j];
                                if (mesh.IsEdgeValid(edgeIndex))
                                {
                                    Edge e = mesh.edges[edgeIndex];
                                    if (mesh.IsEdgeBorder(edgeIndex))
                                    {
                                        borderCenter += mesh.CalculateVertexPairCenter(e);
                                        nBorders     += 1.0f;
                                    }
                                }
                            }
                            vertPoints[i] = 0.5f * oldPosition + borderCenter * (0.5f / nBorders);
                        }
                    }
                }
            }
            else
            {
                // Subdivision without smoothing
                for (int i = 0; i < numVerts; ++i)
                {
                    vertPoints[i] = mesh.vertices[i].coords;
                }
                for (int i = 0; i < numEdges; ++i)
                {
                    edgePoints[i] = mesh.CalculateVertexPairCenter(mesh.edges[i]);
                }
            }
        }