Example #1
0
        public static int GetEdgePointKey(int vi, int vj, MeshStruct meshStruct)
        {
            int qi = meshStruct.FindQuad(vi, vj);
            int qj = meshStruct.FindQuad(vj, vi);

            if (qi > qj)   // quad index may be -1 (if hole)
            {
                return((qi << 3) | (meshStruct.GetIndexInQuad(qi, vi) << 1));
            }
            else
            {
                return((qj << 3) | (meshStruct.GetIndexInQuad(qj, vj) << 1));
            }
        }
Example #2
0
        public MeshData Subdivide()
        {
            // based on:
            // http://www.rorydriscoll.com/2008/08/01/catmull-clark-subdivision-the-basics/
            // https://rosettacode.org/wiki/Catmull%E2%80%93Clark_subdivision_surface

            var newVertices = new Utils.OrderedDictionary <int, Vertex>();

            // reserve indices for new control-points (we need no special unique keys for them)
            for (int vi = 0; vi < vertices.Length; ++vi)
            {
                newVertices.items.Add(default(Vertex));
            }

            // face-point
            for (int qi = 0; qi < meshStruct.quads.Length; ++qi)
            {
                int[]  q            = meshStruct.quads[qi];
                Vertex facePoint    = Average(q.Select(vi => vertices[vi]).ToArray());
                int    facePointKey = GetFacePointKey(qi);
                newVertices.Add(facePointKey, facePoint);
            }

            // edge-point
            var edgeMidPoints = new Dictionary <int, Vertex>();

            for (int qi = 0; qi < meshStruct.quads.Length; ++qi)
            {
                int[] q = meshStruct.quads[qi];
                foreach (int vi in q)
                {
                    int vj           = meshStruct.GetNextInQuad(qi, vi);
                    int edgePointKey = GetEdgePointKey(vi, vj, meshStruct);
                    if (!newVertices.HasKey(edgePointKey))
                    {
                        // edge-midpoint (for control-point calculation)
                        Vertex midPoint = Average(new[] {
                            vertices[vi],
                            vertices[vj],
                        });
                        edgeMidPoints[edgePointKey] = midPoint;
                        // edge-point
                        int qj = meshStruct.FindQuad(vj, vi);
                        if (qj == -1)   // for the edges that are on the border of a hole, the edge point is just the middle of the edge.
                        {
                            newVertices.Add(edgePointKey, midPoint);
                        }
                        else
                        {
                            Vertex edgePoint = Average(new[] {
                                vertices[vi],
                                vertices[vj],
                                newVertices.GetItem(GetFacePointKey(qi)),
                                newVertices.GetItem(GetFacePointKey(qj)),
                            });
                            newVertices.Add(edgePointKey, edgePoint);
                        }
                    }
                }
            }

            // control-point
            for (int vi = 0; vi < vertices.Length; ++vi)
            {
                int[] vjs = meshStruct.GetAllNeighbors(vi);
                // check hole edges
                int[] hvjs = vjs.Where(vj =>
                                       meshStruct.FindQuad(vi, vj) == -1 ||
                                       meshStruct.FindQuad(vj, vi) == -1
                                       ).ToArray();
                if (hvjs.Any())   // hole edge vertices
                // edge-midpoints
                {
                    Vertex edgeMidAverage = Average(hvjs.Select(vj =>
                                                                edgeMidPoints[GetEdgePointKey(vi, vj, meshStruct)]
                                                                ).ToArray());
                    // new control-point
                    Vertex controlPoint = Average(new[] {
                        edgeMidAverage,
                        vertices[vi]
                    });
                    newVertices.items[vi] = controlPoint; // set control-point to reserved index
                }
                else
                {
                    // edge-midpoints
                    Vertex edgeMidAverage = Average(vjs.Select(vj =>
                                                               edgeMidPoints[GetEdgePointKey(vi, vj, meshStruct)]
                                                               ).ToArray());
                    // face-points
                    Vertex faceAverage = Average(meshStruct.vertexQuads[vi].Select(qi =>
                                                                                   newVertices.GetItem(GetFacePointKey(qi))
                                                                                   ).ToArray());
                    // new control-point
                    Vertex controlPoint = Average(new[] {
                        faceAverage,
                        edgeMidAverage,
                        vertices[vi]
                    }, new[] { 1f, 2f, vjs.Length - 3f });
                    newVertices.items[vi] = controlPoint; // set control-point to reserved index
                }
            }

            // new quads
            //           eis[i]
            //     q[i].----.----.q[i+1]
            //         |         |
            // eis[i+3].  fi.    .
            //         |         |
            //         .____.____.
            int ql       = meshStruct.quads.Length;
            var newQuads = new int[ql * 4][];

            for (int qi = 0; qi < ql; ++qi)
            {
                int[] q = meshStruct.quads[qi];
                //
                int   fi  = newVertices.indices[GetFacePointKey(qi)]; // face-point index
                int[] eis = new int[4];                               // edge-point indices
                for (int i = 0; i < 4; ++i)
                {
                    eis[i] = newVertices.indices[GetEdgePointKey(q[i], q[(i + 1) % 4], meshStruct)];
                }
                for (int i = 0; i < 4; ++i)
                {
                    int[] qq = new int[4]; // shift indices (+ i) to keep quad orientation
                    qq[(0 + i) % 4] = q[i];
                    qq[(1 + i) % 4] = eis[i];
                    qq[(2 + i) % 4] = fi;
                    qq[(3 + i) % 4] = eis[(i + 3) % 4];
                    //newQuads[qi * 4 + i] = qq; // less fragmentized quads
                    newQuads[ql * i + qi] = qq; // more fragmentized, but we keep "first quad" (i == 0) indices in quads array
                }
            }

            MeshData md = new MeshData(newVertices.items.ToArray(), newQuads, vertexContent);

            return(md);
        }