Beispiel #1
0
        private static void ComputeEdgeCostAtVertex(ProgMeshVertex v)
        {
            // compute the edge collapse cost for all edges that start
            // from vertex v.  Since we are only interested in reducing
            // the object by selecting the min cost edge at each step, we
            // only cache the cost of the least cost edge at this vertex
            // (in member variable collapse) as well as the value of the
            // cost (in member variable ObjDist).
            if (v.Neighbor.Count == 0)
            {
                // v doesn't have neighbors so it costs nothing to collapse
                v.Collapse = null;
                v.ObjDist  = -0.01f;
                return;
            }

            v.ObjDist  = Constants.FloatMax;
            v.Collapse = null;

            // search all neighboring edges for "least cost" edge
            foreach (var neighbor in v.Neighbor)
            {
                var dist = ComputeEdgeCollapseCost(v, neighbor);
                if (dist < v.ObjDist)
                {
                    v.Collapse = neighbor;                      // candidate for edge collapse
                    v.ObjDist  = dist;                          // cost of the collapse
                }
            }
        }
Beispiel #2
0
        private static float ComputeEdgeCollapseCost(ProgMeshVertex u, ProgMeshVertex v)
        {
            // if we collapse edge uv by moving u to v then how
            // much different will the model change, i.e. how much "error".
            // Texture, vertex normal, and border vertex code was removed
            // to keep this demo as simple as possible.
            // The method of determining cost was designed in order
            // to exploit small and coplanar regions for
            // effective polygon reduction.
            // Is is possible to add some checks here to see if "folds"
            // would be generated.  i.e. normal of a remaining face gets
            // flipped.  I never seemed to run into this problem and
            // therefore never added code to detect this case.

            // find the "sides" triangles that are on the edge uv
            var sides = new List <ProgMeshTriangle>(u.Face.Count);

            foreach (var face in u.Face)
            {
                if (face.HasVertex(v))
                {
                    sides.Add(face);
                }
            }

            // use the triangle facing most away from the sides
            // to determine our curvature term
            var curvature = 0f;

            foreach (var face in u.Face)
            {
                var minCurve = 1f;                 // curve for face i and closer side to it
                foreach (var side in sides)
                {
                    // use dot product of face normals.
                    var dotProd = face.Normal.Dot(side.Normal);
                    minCurve = MathF.Min(minCurve, (1f - dotProd) * 0.5f);
                }

                curvature = MathF.Max(curvature, minCurve);
            }

            // the more coplanar the lower the curvature term
            var edgeLength = v.Position.Sub(u.Position).Magnitude();

            return(edgeLength * curvature);
        }
Beispiel #3
0
        public void RemoveIfNonNeighbor(ProgMeshVertex n)
        {
            // removes n from neighbor Array if n isn't a neighbor.
            if (!Neighbor.Contains(n))
            {
                return;
            }

            foreach (var face in Face)
            {
                if (face.HasVertex(n))
                {
                    return;
                }
            }
            ProgMeshUtil.RemoveFillWithBack(Neighbor, n);
        }
Beispiel #4
0
        private void Collapse(ProgMeshVertex u, ProgMeshVertex v)
        {
            int i;

            // Collapse the edge uv by moving vertex u onto v
            // Actually remove tris on uv, then update tris that
            // have u to have v, and then remove u.
            if (v == null)
            {
                // u is a vertex all by itself so just delete it
                u.Dispose(this);
                return;
            }
            var tmp = new ProgMeshVertex[u.Neighbor.Count];

            // make tmp a Array of all the neighbors of u
            for (i = 0; i < tmp.Length; i++)
            {
                tmp[i] = u.Neighbor[i];
            }

            // delete triangles on edge uv:
            i = u.Face.Count;
            while (i-- > 0)
            {
                if (u.Face[i].HasVertex(v))
                {
                    u.Face[i].Dispose(this);
                }
            }

            // update remaining triangles to have v instead of u
            i = u.Face.Count;
            while (i-- > 0)
            {
                u.Face[i].ReplaceVertex(u, v);
            }
            u.Dispose(this);

            // recompute the edge collapse costs for neighboring vertices
            foreach (var t in tmp)
            {
                ComputeEdgeCostAtVertex(t);
            }
        }
        public void ReplaceVertex(ProgMeshVertex vOld, ProgMeshVertex vNew)
        {
            Debug.Assert(vOld != null && vNew != null, "[ProgMeshTriangle.ReplaceVertex] Arguments must not be null.");
            Debug.Assert(vOld == _vertex[0] || vOld == _vertex[1] || vOld == _vertex[2], "[ProgMeshTriangle.replaceVertex] vOld must not be included in this.vertex.");
            Debug.Assert(vNew != _vertex[0] && vNew != _vertex[1] && vNew != _vertex[2], "[ProgMeshTriangle.replaceVertex] vNew must not be included in this.vertex.");

            if (vOld == _vertex[0])
            {
                _vertex[0] = vNew;
            }
            else if (vOld == _vertex[1])
            {
                _vertex[1] = vNew;
            }
            else
            {
                Debug.Assert(vOld == _vertex[2], "[ProgMeshTriangle.ReplaceVertex] vOld == vertex[2]");
                _vertex[2] = vNew;
            }

            ProgMeshUtil.RemoveFillWithBack(vOld.Face, this);
            Debug.Assert(!vNew.Face.Contains(this), "[ProgMeshTriangle.ReplaceVertex] !Contains(vNew->face, this)");

            vNew.Face.Add(this);

            for (var i = 0; i < 3; i++)
            {
                vOld.RemoveIfNonNeighbor(_vertex[i]);
                _vertex[i].RemoveIfNonNeighbor(vOld);
            }

            for (var i = 0; i < 3; i++)
            {
                Debug.Assert(_vertex[i].Face.Count(f => f == this) == 1, "[ProgMeshTriangle.replaceVertex] Contains(vertex[i]->face, this) == 1");
                for (var j = 0; j < 3; j++)
                {
                    if (i != j)
                    {
                        ProgMeshUtil.AddUnique(_vertex[i].Neighbor, _vertex[j]);
                    }
                }
            }
            ComputeNormal();
        }
        public ProgMeshTriangle(ProgMeshVertex v0, ProgMeshVertex v1, ProgMeshVertex v2)
        {
            Debug.Assert(v0 != null && v1 != null && v2 != null, "[ProgMeshTriangle] Vertices must not be null.");
            Debug.Assert(v0 != v1 && v1 != v2 && v2 != v0, "[ProgMeshTriangle] Vertices must be different.");

            _vertex = new[] { v0, v1, v2 };
            ComputeNormal();

            for (var i = 0; i < 3; i++)
            {
                _vertex[i].Face.Add(this);
                for (var j = 0; j < 3; j++)
                {
                    if (i != j)
                    {
                        ProgMeshUtil.AddUnique(_vertex[i].Neighbor, _vertex[j]);
                    }
                }
            }
        }
 public bool HasVertex(ProgMeshVertex v)
 {
     return(v == _vertex[0] || v == _vertex[1] || v == _vertex[2]);
 }