Beispiel #1
0
    static bool TrianglesToQuads(
        triangleByUV triangles,     // input structure  -> triangle primitives
        quadByUV quads,             // output structure -> quad primitives
        int totalTriangles,         // how many input triangles we have
        ref int totalQuads,         // how many output quads were generated
        string at                   // element we're processing...
        )
    {                               // pair the triangles into quads by max edge connections
        if (triangles == null ||    // no triangle list
            triangles.Count <= 0 || // OR no primitives
            quads == null)          // OR no output list
        {
            return(true);
        }
        // calculate progess amount
        string title       = "Triangle Primitives->Quads " + at;
        float  increment   = 1.0f / (totalTriangles - 1);
        bool   wasCanceled = false;
        int    atTriangle  = 0;
        // sorted by "triangle A connectes to triangle B"
        triangleByQuad connections = new triangleByQuad();

        quads.Clear();
        foreach (Vector2 UV in triangles.Keys)                  // by UV color
        {
            foreach (Vector3 N in triangles[UV].Keys)           // by normal direction
            {
                foreach (Vector2 r in triangles[UV][N].Keys)    // by row in normal direction, axis plane
                {
                    foreach (Triangle A in triangles[UV][N][r]) // triangle A
                    {                                           // go through all listed triangles as A/B
                        atTriangle++;                           // up the current progress
                        if (atTriangle % (totalTriangles / progressUpdates) == 0 &&
                            EditorUtility.DisplayCancelableProgressBar
                                (title, "Searching...", atTriangle * increment))
                        {
                            wasCanceled = true; goto Cancel;
                        }
                        if (!connections.ContainsValue(A))                // not yet listed in quads
                        {
                            foreach (Triangle B in triangles[UV][N][r])   // check all triangles against A
                            {
                                if (A != B &&                             // not self-comparing
                                    !connections.ContainsValue(B) &&      // AND not yet listed in quads
                                    A.maxEdgeVertices.TrueForAll          // AND the same two vertices are in both edge lists
                                        (o => B.maxEdgeVertices.Contains(o)))
                                {                                         // this is the connection A->B, forming a single quad
                                    connections[A] = B;
                                    // figure out the row of the quad
                                    float qr = 0;
                                    if (Mathf.Abs(N.x) > 0.0f)
                                    {
                                        qr = A.A.x;                                                                         // X+,-: YZ plane
                                    }
                                    else if (Mathf.Abs(N.y) > 0.0f)
                                    {
                                        qr = A.A.y;                                                                         // Y+,-: XZ plane
                                    }
                                    else if (Mathf.Abs(N.z) > 0.0f)
                                    {
                                        qr = A.A.z;                                                                         // Z+,-: XY plane
                                    }
                                    // create missing acceleration structure levels
                                    if (!quads.ContainsKey(UV))
                                    {
                                        quads[UV] = new quadByNormal();
                                    }
                                    if (!quads[UV].ContainsKey(N))
                                    {
                                        quads[UV][N] = new quadByRow();
                                    }
                                    if (!quads[UV][N].ContainsKey(qr))
                                    {
                                        quads[UV][N][qr] = new quadByVertex();
                                    }
                                    // now add the quad by "UV->Normal->Row" key
                                    quads[UV][N][qr].Add(
                                        new HashSet <Vector3>
                                            (new Vector3[] { A.A, A.B, A.C, B.A, B.B, B.C })
                                        );
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        // export the amount of generated quad connections
        totalQuads = connections.Count;
Cancel:
        // clear progress bar, signal "wasn't canceled"
        EditorUtility.ClearProgressBar();
        return(wasCanceled);
    }
Beispiel #2
0
    static void Rebuild()
    {
        if (Selection.activeGameObject == null)
        {
            Debug.Log(title + ": Nothing selected."); return;
        }
        List <MeshFilter> all = new List <MeshFilter>();

        foreach (Transform t in Selection.transforms)
        {
            all.AddRange(t.gameObject.GetComponentsInChildren <MeshFilter>());
        }
        if (all == null ||              // no MeshFilter(s)
            all.Count <= 0)             // OR no entries
        {
            Debug.Log(title + ": No mesh(s) on selection."); return;
        }

        int processing = 0;

        foreach (MeshFilter mf in all)
        {
            if (mf != null &&          // instance needs to be valid
                mf.sharedMesh != null) // AND have a shared mesh
            {                          // convert every mesh we find below
                string path = AssetDatabase.GetAssetPath(mf.sharedMesh);
                if (path.ToLower().IndexOf("assets/") < 0)
                {
                    Debug.LogWarning(title + ": Conversion of mesh ['" + path + "'] not supported."); continue;
                }

                processing++;                           // current item we're processing
                bool   cancel = false;                  // did we cancel an operation?
                string at     = "(" + processing + " of " + all.Count + ")";

                // save start timestamp
                double startAt = EditorApplication.timeSinceStartup;
                // sorted by "UV->normal direction->(row, horizontal axis)"->[Triangle list]
                triangleByUV triangles = new triangleByUV();
                // sorted by "UV->normal direction->row"->[List of "Quad vertices list"]
                quadByUV quads = new quadByUV();
                // convert the established mesh to triangle primitives
                float trianglesBefore = (mf.sharedMesh.triangles.Length / 3.0f);
                int   totalTriangles  = 0;
                cancel = MeshToTriangles(mf, triangles, ref totalTriangles, at);
                if (triangles.Count <= 0)
                {
                    Debug.LogError(title + ": Conversion of mesh to Triangle primitives failed."); continue;
                }
                if (cancel)
                {
                    continue;
                }
                // search for quad connections and fill up the quad list
                int totalQuads = 0;
                cancel = TrianglesToQuads(triangles, quads, totalTriangles, ref totalQuads, at);
                if (quads.Count <= 0)
                {
                    Debug.LogError(title + ": Conversion of Triangles->Quads failed."); continue;
                }
                if (cancel)
                {
                    continue;
                }
                // optimize the mesh structure by grouping quads
                cancel = GroupQuads(quads, totalQuads, at);
                if (cancel)
                {
                    continue;
                }
                // spit out the newly generated mesh
                string outputAs = QuadsToMesh(mf, quads, title);
                // print out total time in seconds
                double totalTime      = EditorApplication.timeSinceStartup - startAt;
                float  trianglesAfter = (mf.sharedMesh.triangles.Length / 3.0f);
                float  fRemaining     = (trianglesAfter / trianglesBefore) * 100.0f;
                float  fReduction     = 100.0f - fRemaining;
                Debug.Log(string.Format(
                              "{0}: Done. Processing Time: {1:0.00}s. [Triangles:{2}->{3}, remaining:{4:0.00}%, reduction:{5:0.00}%]",
                              outputAs, totalTime, trianglesBefore, trianglesAfter, fRemaining, fReduction
                              ));
            }
        }
    }
Beispiel #3
0
    const int progressUpdates = 4;   // how often to update the progress bar
    static bool MeshToTriangles(
        MeshFilter mf,               // input mesh source
        triangleByUV triangles,      // output structure -> triangles
        ref int totalTriangles,      // amount of triangles we're processing
        string at                    // element we're processing...
        )
    {                                // convert an established mesh into a complex list of Triangle primitives
        if (mf == null ||            // no MeshFilter
            mf.sharedMesh == null || // OR no shared mesh
            triangles == null)       // OR no output list
        {
            return(true);
        }
        // get the triangles from the established mesh
        int[]     f  = mf.sharedMesh.triangles;
        Vector3[] v  = mf.sharedMesh.vertices;
        Vector3[] n  = mf.sharedMesh.normals;
        Vector2[] uv = mf.sharedMesh.uv;
        triangles.Clear();
        string title       = "Mesh->Triangle Primitives " + at;
        float  increment   = 1.0f / (f.Length - 1);
        bool   wasCanceled = false;

        totalTriangles = f.Length / 3;
        for (int i = 0; i < f.Length; i += 3)
        {         // create triangle primitives from all faces
            if (i % (f.Length / progressUpdates) == 0 &&
                EditorUtility.DisplayCancelableProgressBar
                    (title, "Converting...", i * increment))
            {
                wasCanceled = true; break;
            }
            int     A  = f[i + 0];
            int     B  = f[i + 1];
            int     C  = f[i + 2];
            Vector3 UV = uv[A];
            Vector3 N  = n [A].normalized;
            // winding cannot be trusted. we need to calculate a lot on the go
            Triangle t = new Triangle(v[A], v[B], v[C]);
            Vector2  r = Vector2.zero;
            if (Mathf.Abs(N.x) > 0.0f)
            {
                r = new Vector2(t.A.x, t.A.z);                                        // X+,-: YZ plane, search Z dir
            }
            else if (Mathf.Abs(N.y) > 0.0f)
            {
                r = new Vector2(t.A.y, t.A.x);                                        // Y+,-: XZ plane, search X dir
            }
            else if (Mathf.Abs(N.z) > 0.0f)
            {
                r = new Vector2(t.A.z, t.A.x);                                        // Z+,-: XY plane, search X dir
            }
            // create missing acceleration structure levels
            if (!triangles.ContainsKey(UV))
            {
                triangles[UV] = new triangleByNormal();
            }
            if (!triangles[UV].ContainsKey(N))
            {
                triangles[UV][N] = new triangleByRow();
            }
            if (!triangles[UV][N].ContainsKey(r))
            {
                triangles[UV][N][r] = new triangleByList();
            }
            // now finally add triangle by "UV->Normal->Row" key
            triangles[UV][N][r].Add(t);
        }
        // clear progress bar, signal "wasn't canceled"
        EditorUtility.ClearProgressBar();
        return(wasCanceled);
    }