Ejemplo n.º 1
0
        // compact triangles, compute edge error and build reference list

        void Update_mesh(int iteration)
        {
            if (iteration > 0) // compact triangles
            {
                int dst = 0;
                for (int i = 0; i < triangles.Count; i++)
                {
                    if (triangles[i].deleted == 0)
                    {
                        triangles[dst++] = triangles[i];
                    }
                }
            }
            //
            // Init Quadrics by Plane & Edge Errors
            //
            // required at the beginning ( iteration == 0 )
            // recomputing during the simplification is not required,
            // but mostly improves the result for closed meshes
            //
            if (iteration == 0)
            {
                for (int i = 0; i < vertices.Count; i++)
                {
                    Vertex v = vertices[i];
                    v.q         = new SymetricMatrix(0.0);
                    vertices[i] = v;
                }

                for (int i = 0; i < triangles.Count; i++)
                {
                    Triangle  t = triangles[i];
                    Vector3   n = new Vector3();
                    Vector3[] p = new Vector3[3];
                    for (int j = 0; j < 3; j++)
                    {
                        p[j] = vertices[t.v[j]].p;
                    }
                    n = Vector3.Cross(p[1] - p[0], p[2] - p[0]);
                    n.Normalize();
                    t.n = n;
                    for (int j = 0; j < 3; j++)
                    {
                        Vertex v = vertices[t.v[j]];
                        v.q = vertices[t.v[j]].q + new SymetricMatrix(n.X, n.Y, n.Z, -Vector3.Dot(n, p[0]));
                        vertices[t.v[j]] = v;
                    }
                    triangles[i] = t;
                }
                for (int i = 0; i < triangles.Count; i++)
                {
                    // Calc Edge Error
                    Triangle t = triangles[i];
                    Vector3  p = new Vector3();
                    for (int j = 0; j < 3; j++)
                    {
                        t.err[j] = Calculate_error(t.v[j], t.v[(j + 1) % 3], ref p);
                    }
                    t.err[3]     = Math.Min(t.err[0], Math.Min(t.err[1], t.err[2]));
                    triangles[i] = t;
                }
            }

            // Init Reference ID list
            for (int i = 0; i < vertices.Count; i++)
            {
                Vertex v = vertices[i];
                v.tstart    = 0;
                v.tcount    = 0;
                vertices[i] = v;
            }
            for (int i = 0; i < triangles.Count; i++)
            {
                Triangle t = triangles[i];
                for (int j = 0; j < 3; i++)
                {
                    Vertex v = vertices[t.v[j]];
                    v.tcount++;
                    vertices[t.v[j]] = v;
                }
            }
            int tstart = 0;

            for (int i = 0; i < vertices.Count; i++)
            {
                Vertex v = vertices[i];
                v.tstart    = tstart;
                tstart     += v.tcount;
                v.tcount    = 0;
                vertices[i] = v;
            }

            // Write References
            for (int i = 0; i < triangles.Count; i++)
            {
                Triangle t = triangles[i];
                for (int j = 0; j < 3; j++)
                {
                    Vertex v = vertices[t.v[j]];
                    Ref    r = refs[v.tstart + v.tcount];
                    r.tid     = i;
                    r.tvertex = j;
                    refs[v.tstart + v.tcount] = r;
                    v.tcount++;
                    vertices[t.v[j]] = v;
                }
                triangles[i] = t;
            }

            // Identify boundary : vertices[].border=0,1
            if (iteration == 0)
            {
                ListHelper <int> vcount = new ListHelper <int>();
                ListHelper <int> vids   = new ListHelper <int>();

                for (int i = 0; i < vertices.Count; i++)
                {
                    Vertex v = vertices[i];
                    v.border    = 0;
                    vertices[i] = v;
                }

                for (int i = 0; i < vertices.Count; i++)
                {
                    Vertex v = vertices[i];
                    vcount.Clear();
                    vids.Clear();
                    for (int j = 0; j < v.tcount; j++)
                    {
                        int      kb = refs[v.tstart + j].tid;
                        Triangle t  = triangles[kb];
                        for (int k = 0; k < 3; k++)
                        {
                            int ofs = 0, id = t.v[k];
                            while (ofs < vcount.Count)
                            {
                                if (vids[ofs] == id)
                                {
                                    break;
                                }
                                ofs++;
                            }
                            if (ofs == vcount.Count)
                            {
                                vcount.Add(1);
                                vids.Add(id);
                            }
                            else
                            {
                                vcount[ofs]++;
                            }
                        }
                        triangles[kb] = t;
                    }
                    for (int j = 0; j < vcount.Count; j++)
                    {
                        if (vcount[j] == 1)
                        {
                            Vertex vt = vertices[vids[j]];
                            vt.border         = 1;
                            vertices[vids[j]] = vt;
                        }
                    }
                }
            }
        }
Ejemplo n.º 2
0
        // Main simplification function
        //
        // target_count  : target nr. of triangles
        // agressiveness : sharpness to increase the threashold.
        //                 5..8 are good numbers
        //                 more iterations yield higher quality
        //
        void Simplify_mesh(int target_count, double agressiveness = 7)
        {
            // main iteration loop

            int deleted_triangles     = 0;
            ListHelper <int> deleted0 = new ListHelper <int>();
            ListHelper <int> deleted1 = new ListHelper <int>();
            int triangle_count        = triangles.Count;

            for (int iteration = 0; iteration < 100; iteration++)
            {
                // target number of triangles reached ? Then break
                if (triangle_count - deleted_triangles <= target_count)
                {
                    break;
                }

                // update mesh once in a while
                if (iteration % 5 == 0)
                {
                    Update_mesh(iteration);
                }

                // clear dirty flag
                for (int i = 0; i < triangles.Count; i++)
                {
                    Triangle t = triangles[i];
                    t.dirty      = 0;
                    triangles[i] = t;
                }

                //
                // All triangles with edges below the threshold will be removed
                //
                // The following numbers works well for most models.
                // If it does not, try to adjust the 3 parameters
                //
                double threshold = 0.000000001 * Math.Pow((double)(iteration + 3), agressiveness);

                // remove vertices & mark deleted triangles
                for (int i = 0; i < triangles.Count; i++)
                {
                    Triangle t = triangles[i];
                    if (t.err[3] > threshold)
                    {
                        continue;
                    }
                    if (t.deleted != 0)
                    {
                        continue;
                    }
                    if (t.dirty != 0)
                    {
                        continue;
                    }

                    for (int j = 0; j < 3; j++)
                    {
                        if (t.err[j] < threshold)
                        {
                            int    i0 = t.v[j];
                            Vertex v0 = vertices[i0];
                            int    i1 = t.v[(j + 1) % 3];
                            Vertex v1 = vertices[i1];

                            // Border check
                            if (v0.border != v1.border)
                            {
                                continue;
                            }

                            // Compute vertex to collapse to
                            Vector3 p = new Vector3();
                            Calculate_error(i0, i1, ref p);

                            // dont remove if flipped
                            if (Flipped(p, i0, i1, ref v0, ref v1, ref deleted0))
                            {
                                continue;
                            }
                            if (Flipped(p, i1, i0, ref v1, ref v0, ref deleted1))
                            {
                                continue;
                            }

                            // not flipped, so remove edge
                            v0.p = p;
                            v0.q = v1.q + v0.q;
                            int tstart = refs.Count;

                            Update_triangles(i0, ref v0, ref deleted0, ref deleted_triangles);
                            Update_triangles(i0, ref v1, ref deleted1, ref deleted_triangles);

                            vertices[i0] = v0;
                            vertices[i1] = v1;

                            int tcount = refs.Count - tstart;

                            if (tcount <= v0.tcount)
                            {
                                // save ram
                                if (tcount != 0)
                                {
                                    for (int f = 0; f < tcount; f++)
                                    {
                                        refs[v0.tstart + f] = refs[tstart];
                                    }
                                }
                            }
                            else
                            {
                                // append
                                v0.tstart = tstart;
                            }

                            v0.tcount = tcount;
                            break;
                        }
                    }
                    triangles[i] = t;
                    // done?
                    if (triangle_count - deleted_triangles <= target_count)
                    {
                        break;
                    }
                }
            }

            // clean up mesh
            Compact_mesh();
        }