예제 #1
0
    public void Apply(RenderGeometry geometry)
    {
        foreach (Face face in geometry.faces)
        {
            Vector3 faceCenter = face.CalculateCenter();

            foreach (Halfedge edge in face.edges)
            {
                geometry.SetNormal(edge, geometry.GetEffectiveNormal(edge) + (edge.vertex.p - faceCenter).normalized * curvature);
            }
            geometry.SetFaceType(face, RenderGeometry.FaceType.Smooth);
        }
    }
예제 #2
0
    public void Apply(RenderGeometry geometry)
    {
        var splitHalfedges = new HashSet <Halfedge>(geometry.halfedges.Where(e => IsValidEdge(e, geometry)));
        var additionalBoundaryHalfedges = new HashSet <Halfedge>();
        var splitVertices = splitHalfedges.Select(e => e.vertex).Distinct().ToArray();

        var splitHalfedgeToNewVertexPosition       = new Dictionary <Halfedge, Vector3>();
        var splitHalfedgeToVertexNormal            = new Dictionary <Halfedge, Vector3>();
        var splitHalfedgeToPreviousOpposite        = new Dictionary <Halfedge, Halfedge>();
        var splitVertexToSurroundingSplitHalfedges = new Dictionary <Vertex, Halfedge[]>();

        // Precalculates new vertex positions. Memorize old normals and old opposites of split halfedges.
        foreach (Halfedge edge in splitHalfedges)
        {
            Halfedge nextSplitEdge = NextEdgeThat(edge, e => splitHalfedges.Contains(e) || e.isBoundary);
            if (nextSplitEdge != edge)
            {
                splitHalfedgeToNewVertexPosition[edge] = CalculateVertexPosition(edge, nextSplitEdge.opposite, geometry);
                if (nextSplitEdge.isBoundary)
                {
                    Halfedge otherEdge          = nextSplitEdge.next.opposite;
                    Halfedge otherNextSplitEdge = NextEdgeThat(edge, e => splitHalfedges.Contains(e));
                    splitHalfedgeToNewVertexPosition[otherEdge] = CalculateVertexPosition(otherEdge, otherNextSplitEdge.opposite, geometry);

                    additionalBoundaryHalfedges.Add(otherEdge);
                    splitHalfedgeToVertexNormal[otherEdge] = geometry.GetEffectiveNormal(otherEdge);
                }
            }
            else
            {
                splitHalfedgeToNewVertexPosition[edge] = edge.vertex.p;
            }
            splitHalfedgeToVertexNormal[edge]     = geometry.GetEffectiveNormal(edge);
            splitHalfedgeToPreviousOpposite[edge] = edge.opposite;
        }

        // Memorize the old connected split halfedges around any given split vertex.
        foreach (Vertex vertex in splitVertices)
        {
            splitVertexToSurroundingSplitHalfedges[vertex] = vertex.edges.Where(e => splitHalfedges.Contains(e) || additionalBoundaryHalfedges.Contains(e)).ToArray();
        }

        // Split the geometry. A pair of halfedges only needs to be split once.
        foreach (Halfedge edge in splitHalfedges)
        {
            if (!edge.opposite.isBoundary)
            {
                geometry.DisconnectEdge(edge);
            }
        }

        // Set new vertex positions
        foreach (Halfedge edge in splitHalfedges.Concat(additionalBoundaryHalfedges))
        {
            edge.vertex.p = splitHalfedgeToNewVertexPosition[edge];
        }

        var vertexNormals = splitHalfedgeToVertexNormal.ToDictionary(entry => entry.Key.vertex, entry => entry.Value);

        void AddFace(params Vertex[] faceVertices)
        {
            Face newFace = geometry.CreateFace(faceVertices.ToArray());

            geometry.SetFaceType(newFace, RenderGeometry.FaceType.Smooth);
            newFace.edges.ForEach(e => geometry.SetNormal(e, vertexNormals[e.vertex]));
        }

        // Create one edge face for each split edge.
        foreach (Halfedge edge in splitHalfedges)
        {
            if (!edge.opposite.isBoundary)
            {
                continue;
            }

            Halfedge otherEdge    = splitHalfedgeToPreviousOpposite[edge];
            var      faceVertices = new List <Vertex>();
            AddIfNotPresent(faceVertices, edge.vertex);
            AddIfNotPresent(faceVertices, edge.prev.vertex);
            AddIfNotPresent(faceVertices, otherEdge.vertex);
            AddIfNotPresent(faceVertices, otherEdge.prev.vertex);

            if (faceVertices.Count >= 3)
            {
                AddFace(faceVertices.ToArray());
            }
        }

        // Create one corner face for each split vertex.
        foreach (Vertex vertex in splitVertices)
        {
            Halfedge[] surroundingSplitHalfedges = splitVertexToSurroundingSplitHalfedges[vertex];
            int        n = surroundingSplitHalfedges.Length;
            if (n < 3)
            {
                continue;
            }

            Vertex[] faceVertices = surroundingSplitHalfedges.Select(e => e.vertex).Reverse().ToArray();
            if (n == 3)
            {
                AddFace(faceVertices.ToArray());
            }
            else
            {
                Vertex faceCenter = geometry.CreateVertex(faceVertices.Average(v => v.p));
                vertexNormals[faceCenter] = faceVertices.Average(v => vertexNormals[v]).normalized;
                for (int i = 0; i < n; i++)
                {
                    AddFace(faceVertices[i], faceVertices[(i + 1) % n], faceCenter);
                }
            }
        }
    }