Пример #1
0
    private void OnSceneGUI()
    {
        var area = target as Area;

        if (area.Corners.Count <= 2)
        {
            return;
        }

        Handles.color = Color.white;

        var triangles = Delaunay.Triangulate(area.Corners);

        foreach (var tri in triangles)
        {
            var pts = tri.ToVertexList().Select(p => new Vector3(p.x, 0f, p.y)).ToList();
            pts.Add(pts[0]);
            for (int i = 0; i < 3; ++i)
            {
                Handles.DrawLine(pts[i], pts[i + 1]);
            }
        }

        Handles.color = Color.blue;
        for (int i = 0; i < area.Corners.Count; ++i)
        {
            ShowCorner(area, i);
        }
    }
Пример #2
0
    public Triangle[] Delaunay()
    {
        Vertex[] apexs    = GetAllDelaunayApex();
        Delaunay delaunay = new Delaunay();

        delaunay.Triangulate(apexs);
        //为三角形添加颜色
        var tris = delaunay.Triangles;

        SampleColor(tris);
        return(tris.ToArray());
    }
Пример #3
0
 // Update is called once per frame
 void Update()
 {
     if (!allComplete)
     {
         if (!hasStarted)
         {
             if (cellsStill())
             {
                 hasStarted = true;
             }
         }
         else
         {
             if (!isFinished)
             {
                 setRooms();
                 m_delaunayController.Initialize(roomList);
                 isFinished = true;
             }
             else
             {
                 if (!DTFinished)
                 {
                     if (!m_delaunayController.IsTriangulationComplete())
                     {
                         m_delaunayController.Triangulate();
                     }
                     else
                     {
                         DTFinished = true;
                         m_mstController.Initialize(roomList, m_delaunayController.GetTriangulation());
                     }
                 }
                 else
                 {
                     if (!PrimFinished)
                     {
                         m_mstController.Update();
                         PrimFinished = true;
                         m_worldForge = new WorldForge(cellList, roomList, m_mstController);
                     }
                     else
                     {
                         m_worldForge.Create();
                         allComplete = true;
                     }
                 }
             }
         }
     }
 }
Пример #4
0
    public void Awake()
    {
        _triangles = new List <Triangle>();
        _triangles.AddRange(Delaunay.Triangulate(Corners));
        _areaSum = 0f;
        _triangles.ForEach(x => _areaSum += x.TriArea());

        foreach (var tri in _triangles)
        {
            var pts = tri.ToVertexList().Select(p => new Vector3(p.x, 0f, p.y)).ToList();
            pts.Add(pts[0]);
            _linesToDraw[tri] = pts;
        }
    }
Пример #5
0
        /**
         * Re-triangulates a face with existing indices and vertices.
         */
        public static void TriangulateFace(this pb_Object pb, pb_Face face, Vector3?projectionAxis)
        {
            int[] orig = face.indices;

            Vector3[] v3d = pbUtil.ValuesWithIndices(pb.vertices, orig);
            Vector3   nrm = (Vector3)(projectionAxis ?? Vector3.Cross(v3d[2] - v3d[0], v3d[1] - v3d[0]));

            Vector2[] v2d = pb_Math.PlanarProject(v3d, nrm);

            int[] tris = Delaunay.Triangulate(new List <Vector2>(v2d)).ToIntArray();

            int[] new_indices = new int[tris.Length];

            for (int i = 0; i < tris.Length; i++)
            {
                new_indices[i] = orig[tris[i]];
            }

            face.SetIndices(new_indices);
        }
    public World GenerateGoodDungeon()
    {
        int     roomGenerationRadius = 30;
        Int2    roomSize;
        Vector2 roomPoint;

        Collections.allRooms = new List <Room>();
        for (int i = 0; i < 150; i++)
        {
            roomSize  = new Int2((int)Utilities.NormalizedRandom(18, 48), (int)Utilities.NormalizedRandom(12, 36));
            roomPoint = Utilities.RandomPointInCircle(roomGenerationRadius);

            Collections.allRooms.Add(new Room(roomPoint, roomSize));
        }

        for (int i = 0; i < 5; i++)
        {
            SeparateRooms();
        }

        int roomCount = Collections.allRooms.Count;

        for (int i = 0; i < roomCount; i++)
        {
            for (int j = i + 1; j < roomCount; j++)
            {
                if (Collections.allRooms[i] == null || Collections.allRooms[j] == null)
                {
                    continue;
                }

                if (Collections.allRooms[i].TooCloseTo(Collections.allRooms[j]))
                {
                    Collections.allRooms[i] = null;
                }
            }
        }

        Collections.allRooms.RemoveAll(room => room == null);
        Collections.allRooms.RemoveAll(room => room.size.x < 24 || room.size.y < 16);


        int minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue;

        foreach (Room room in Collections.allRooms)
        {
            if (room.position.x < minX)
            {
                minX = (int)room.position.x;
            }
            if (room.position.y < minY)
            {
                minY = (int)room.position.y;
            }
            if (room.position.x > maxX)
            {
                maxX = (int)room.position.x;
            }
            if (room.position.y > maxY)
            {
                maxY = (int)room.position.y;
            }
        }

        int   border   = 128;
        int   width    = maxX - minX + 2 * border;
        int   height   = maxY - minY + 2 * border;
        Int2  offset   = new Int2(width / 2, height / 2);
        World newWorld = new World("Dungeon", width, height);

        world = newWorld;

        Collections.allRooms.ForEach(x => x.position += offset.ToVector2());

        Collections.allRooms = Collections.allRooms.OrderBy(point => point.position.x).ToList();
        Triangle            superTriangle     = Delaunay.SuperTriangle(Collections.allRooms);
        List <Triangle>     delauneyTriangles = Delaunay.Triangulate(superTriangle, Collections.allRooms);
        List <DelaunayEdge> delaunayEdges     = Delaunay.DelaunayEdges(superTriangle, delauneyTriangles);

        Graph <int> W = new Graph <int>(Enumerable.Range(0, delaunayEdges.Count));

        foreach (DelaunayEdge edge in delaunayEdges)
        {
            W.SetEdge(edge.start, edge.end,
                      (int)Mathf.Sqrt(
                          (Collections.allRooms[edge.start].position.x -
                           Collections.allRooms[edge.end].position.x) *
                          (Collections.allRooms[edge.start].position.x -
                           Collections.allRooms[edge.end].position.x) +
                          (Collections.allRooms[edge.start].position.y -
                           Collections.allRooms[edge.end].position.y) *
                          (Collections.allRooms[edge.start].position.y -
                           Collections.allRooms[edge.end].position.y)));
        }

        Prim <int> prim = new Prim <int>();
        Dictionary <Graph <int> .Node, Graph <int> .Node> tree = new Dictionary <Graph <int> .Node, Graph <int> .Node>();

        prim.prim(W, W.FindVertex(0), ref tree);

        Tile tile = new Tile(12);

        StaticWorld(tile, tile);

        foreach (Room room in Collections.allRooms)
        {
            Rectangle((int)(room.position.x - room.size.x / 2f), (int)(room.position.y - room.size.y / 2f),
                      room.size.x, room.size.y);
        }

        foreach (KeyValuePair <Graph <int> .Node, Graph <int> .Node> kv in tree)
        {
            //Debug.DrawLine(Collections.allRooms[kv.Key.context].position,
            //Collections.allRooms[kv.Value.context].position, Color.red, 100f);

            Int2 startPoint = new Int2((int)Collections.allRooms[kv.Key.context].position.x,
                                       (int)Collections.allRooms[kv.Key.context].position.y);
            Int2 endPoint = new Int2((int)Collections.allRooms[kv.Value.context].position.x,
                                     (int)Collections.allRooms[kv.Value.context].position.y);

            Hallway(startPoint, endPoint);
        }


        return(newWorld);
    }
Пример #7
0
        /**
         *	Inserts a vertex at the center of each edge, then connects the new vertices to another new
         *	vertex placed at the center of the face.
         */
        private static bool SubdivideFace_Internal(pb_Object pb, pb_EdgeConnection pb_edgeConnection,
                                                   out DanglingVertex?[] appendedVertices,
                                                   out pb_Face[] splitFaces,
                                                   out Vector3[][] splitVertices,
                                                   out Color[][] splitColors,
                                                   out Vector2[][] splitUVs,
                                                   out int[][] splitSharedIndices)
        {
            splitFaces         = null;
            splitVertices      = null;
            splitColors        = null;
            splitUVs           = null;
            splitSharedIndices = null;
            appendedVertices   = new DanglingVertex?[pb_edgeConnection.edges.Count];

            // cache all the things
            pb_Face face = pb_edgeConnection.face;
            Dictionary <int, int> sharedIndices = pb.sharedIndices.ToDictionary();

            Vector3[] vertices = pb.vertices;
            Vector2[] uvs      = pb.uv;

            List <Vector2> edgeCentersUV  = new List <Vector2>();
            List <Vector3> edgeCenters3d  = new List <Vector3>();
            List <Color>   edgeCentersCol = new List <Color>();

            // filter duplicate edges
            int        u = 0;
            List <int> usedEdgeIndices = new List <int>();

            foreach (pb_Edge edge in pb_edgeConnection.edges)
            {
                int ind = face.edges.IndexOf(edge, sharedIndices);
                if (!usedEdgeIndices.Contains(ind))
                {
                    Vector3 cen = (vertices[edge.x] + vertices[edge.y]) / 2f;

                    appendedVertices[u] = new DanglingVertex(cen, (pb.colors[edge.x] + pb.colors[edge.y]) / 2f);

                    edgeCenters3d.Add(cen);
                    edgeCentersUV.Add((uvs[edge.x] + uvs[edge.y]) / 2f);
                    edgeCentersCol.Add((pb.colors[edge.x] + pb.colors[edge.y]) / 2f);

                    usedEdgeIndices.Add(ind);
                }
                else
                {
                    appendedVertices[u] = null;
                }

                u++;
            }

            // now we have all the vertices of the old face, plus the new edge center vertices
            Vector3 nrm = pb_Math.Normal(pb.GetVertices(face.indices));

            Vector3[] verts3d = pb.GetVertices(face.distinctIndices);
            Vector2[] faceUVs = pb.GetUVs(face.distinctIndices);
            Color[]   colors  = pbUtil.ValuesWithIndices(pb.colors, face.distinctIndices);

            Vector2[] verts2d       = pb_Math.PlanarProject(verts3d, nrm);
            Vector2[] edgeCenters2d = pb_Math.PlanarProject(edgeCenters3d.ToArray(), nrm);

            Vector3 cen3d = pb_Math.Average(verts3d);
            Vector2 cenUV = pb_Bounds2D.Center(faceUVs);

            Vector2 cen2d = pb_Math.PlanarProject(new Vector3[1] {
                cen3d
            }, nrm)[0];

            // Get the directions from which to segment this face
            Vector2[] dividers = new Vector2[edgeCenters2d.Length];
            for (int i = 0; i < edgeCenters2d.Length; i++)
            {
                dividers[i] = (edgeCenters2d[i] - cen2d).normalized;
            }

            List <Vector2>[] quadrants2d  = new List <Vector2> [edgeCenters2d.Length];
            List <Vector3>[] quadrants3d  = new List <Vector3> [edgeCenters2d.Length];
            List <Vector2>[] quadrantsUV  = new List <Vector2> [edgeCenters2d.Length];
            List <Color>[]   quadrantsCol = new List <Color> [edgeCenters2d.Length];

            List <int>[] sharedIndex = new List <int> [edgeCenters2d.Length];

            for (int i = 0; i < quadrants2d.Length; i++)
            {
                quadrants2d[i] = new List <Vector2>(1)
                {
                    cen2d
                };
                quadrants3d[i] = new List <Vector3>(1)
                {
                    cen3d
                };
                quadrantsUV[i] = new List <Vector2>(1)
                {
                    cenUV
                };
                quadrantsCol[i] = new List <Color>(1)
                {
                    pb_Math.Average(pbUtil.ValuesWithIndices(pb.colors, face.distinctIndices))
                };

                sharedIndex[i] = new List <int>(1)
                {
                    -2
                };                                                              // any negative value less than -1 will be treated as a new group
            }

            // add the divisors
            for (int i = 0; i < edgeCenters2d.Length; i++)
            {
                quadrants2d[i].Add(edgeCenters2d[i]);
                quadrants3d[i].Add(edgeCenters3d[i]);
                quadrantsUV[i].Add(edgeCentersUV[i]);
                quadrantsCol[i].Add(edgeCentersCol[i]);

                sharedIndex[i].Add(-1);

                // and add closest in the counterclockwise direction
                Vector2 dir = (edgeCenters2d[i] - cen2d).normalized;
                float   largestClockwiseDistance = 0f;
                int     quad = -1;
                for (int j = 0; j < dividers.Length; j++)
                {
                    if (j == i)
                    {
                        continue;                       // this is a dividing vertex - ignore
                    }
                    float dist = Vector2.Angle(dividers[j], dir);
                    if (Vector2.Dot(pb_Math.Perpendicular(dividers[j]), dir) < 0f)
                    {
                        dist = 360f - dist;
                    }

                    if (dist > largestClockwiseDistance)
                    {
                        largestClockwiseDistance = dist;
                        quad = j;
                    }
                }

                quadrants2d[quad].Add(edgeCenters2d[i]);
                quadrants3d[quad].Add(edgeCenters3d[i]);
                quadrantsUV[quad].Add(edgeCentersUV[i]);
                quadrantsCol[quad].Add(edgeCentersCol[i]);

                sharedIndex[quad].Add(-1);
            }

            // distribute the existing vertices
            for (int i = 0; i < face.distinctIndices.Length; i++)
            {
                Vector2 dir = (verts2d[i] - cen2d).normalized;          // plane corresponds to distinctIndices
                float   largestClockwiseDistance = 0f;
                int     quad = -1;
                for (int j = 0; j < dividers.Length; j++)
                {
                    float dist = Vector2.Angle(dividers[j], dir);
                    if (Vector2.Dot(pb_Math.Perpendicular(dividers[j]), dir) < 0f)
                    {
                        dist = 360f - dist;
                    }

                    if (dist > largestClockwiseDistance)
                    {
                        largestClockwiseDistance = dist;
                        quad = j;
                    }
                }

                quadrants2d[quad].Add(verts2d[i]);
                quadrants3d[quad].Add(verts3d[i]);
                quadrantsUV[quad].Add(faceUVs[i]);
                quadrantsCol[quad].Add(colors[i]);

                sharedIndex[quad].Add(sharedIndices[face.distinctIndices[i]]);
            }

            int len = quadrants2d.Length;

            // Triangulate
            int[][] tris = new int[len][];
            for (int i = 0; i < len; i++)
            {
                if (quadrants2d[i].Count < 3)
                {
                    Debug.LogError("Insufficient points to triangulate.  Exit subdivide operation.  This is probably due to a concave face.");
                    return(false);
                }

                tris[i] = Delaunay.Triangulate(quadrants2d[i]).ToIntArray();

                if (tris[i].Length < 3)         ///< #521
                {
                    return(false);
                }

                if (Vector3.Dot(nrm, pb_Math.Normal(quadrants3d[i][tris[i][0]], quadrants3d[i][tris[i][1]], quadrants3d[i][tris[i][2]])) < 0)
                {
                    System.Array.Reverse(tris[i]);
                }
            }

            splitFaces         = new pb_Face[len];
            splitVertices      = new Vector3[len][];
            splitColors        = new Color[len][];
            splitUVs           = new Vector2[len][];
            splitSharedIndices = new int[len][];

            for (int i = 0; i < len; i++)
            {
                // triangles, material, pb_UV, smoothing group, shared index
                splitFaces[i]    = new pb_Face(tris[i], face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, face.elementGroup, face.manualUV);
                splitVertices[i] = quadrants3d[i].ToArray();
                splitColors[i]   = quadrantsCol[i].ToArray();
                splitUVs[i]      = quadrantsUV[i].ToArray();

                splitSharedIndices[i] = sharedIndex[i].ToArray();
            }

            return(true);
        }
Пример #8
0
        /**
         *	This method assumes that the split selection edges share a common face and have already been sanity checked.  Will return
         *	the variables necessary to compose a new face from the split, or null if the split is invalid.
         */
        private static bool SplitFace_Internal(SplitSelection splitSelection,
                                               out pb_Face[] splitFaces,
                                               out Vector3[][] splitVertices,
                                               out Color[][] splitColors,
                                               out Vector2[][] splitUVs,
                                               out int[][] splitSharedIndices)
        {
            splitFaces         = null;
            splitVertices      = null;
            splitColors        = null;
            splitUVs           = null;
            splitSharedIndices = null;

            pb_Object pb   = splitSelection.pb;         // we'll be using this a lot
            pb_Face   face = splitSelection.face;       // likewise

            int[]         indices       = face.distinctIndices;
            pb_IntArray[] sharedIndices = pb.sharedIndices;
            int[]         sharedIndex   = new int[indices.Length];
            for (int i = 0; i < indices.Length; i++)
            {
                sharedIndex[i] = sharedIndices.IndexOf(indices[i]);
            }

            // First order of business is to translate the face to 2D plane.
            Vector3[] verts  = pb.GetVertices(face.distinctIndices);
            Color[]   colors = pbUtil.ValuesWithIndices(pb.colors, face.distinctIndices);
            Vector2[] uvs    = pb.GetUVs(face.distinctIndices);

            Vector3 projAxis = pb_Math.ProjectionAxisToVector(pb_Math.VectorToProjectionAxis(pb_Math.Normal(pb, face)));

            Vector2[] plane = pb_Math.PlanarProject(verts, projAxis);

            // Split points
            Vector3 splitPointA_3d = splitSelection.pointA;
            Vector3 splitPointB_3d = splitSelection.pointB;

            Vector2 splitPointA_uv = splitSelection.aIsVertex ? pb.uv[splitSelection.indexA[0]] : (pb.uv[splitSelection.indexA[0]] + pb.uv[splitSelection.indexA[1]]) / 2f;
            Vector2 splitPointB_uv = splitSelection.bIsVertex ? pb.uv[splitSelection.indexB[0]] : (pb.uv[splitSelection.indexB[0]] + pb.uv[splitSelection.indexB[1]]) / 2f;

            Vector2 splitPointA_2d = pb_Math.PlanarProject(new Vector3[1] {
                splitPointA_3d
            }, projAxis)[0];
            Vector2 splitPointB_2d = pb_Math.PlanarProject(new Vector3[1] {
                splitPointB_3d
            }, projAxis)[0];

            List <Vector3> v_polyA = new List <Vector3>();      // point in object space
            List <Vector3> v_polyB = new List <Vector3>();      // point in object space

            List <Color> c_polyA = new List <Color>();
            List <Color> c_polyB = new List <Color>();

            List <Vector2> v_polyB_2d = new List <Vector2>();   // point in 2d space - used to triangulate
            List <Vector2> v_polyA_2d = new List <Vector2>();   // point in 2d space - used to triangulate

            List <Vector2> u_polyA = new List <Vector2>();
            List <Vector2> u_polyB = new List <Vector2>();

            List <int> i_polyA = new List <int>();                      // sharedIndices array index
            List <int> i_polyB = new List <int>();                      // sharedIndices array index

            List <int> nedgeA = new List <int>();
            List <int> nedgeB = new List <int>();

            // Sort points into two separate polygons
            for (int i = 0; i < indices.Length; i++)
            {
                // is this point (a) a vertex to split or (b) on the negative or positive side of this split line
                if ((splitSelection.aIsVertex && splitSelection.indexA[0] == indices[i]) || (splitSelection.bIsVertex && splitSelection.indexB[0] == indices[i]))
                {
                    v_polyA.Add(verts[i]);
                    v_polyB.Add(verts[i]);

                    u_polyA.Add(uvs[i]);
                    u_polyB.Add(uvs[i]);

                    v_polyA_2d.Add(plane[i]);
                    v_polyB_2d.Add(plane[i]);

                    i_polyA.Add(sharedIndex[i]);
                    i_polyB.Add(sharedIndex[i]);

                    c_polyA.Add(colors[i]);
                    c_polyB.Add(colors[i]);
                }
                else
                {
                    // split points across the division line
                    Vector2 perp   = pb_Math.Perpendicular(splitPointB_2d, splitPointA_2d);
                    Vector2 origin = (splitPointA_2d + splitPointB_2d) / 2f;

                    if (Vector2.Dot(perp, plane[i] - origin) > 0)
                    {
                        v_polyA.Add(verts[i]);
                        v_polyA_2d.Add(plane[i]);
                        u_polyA.Add(uvs[i]);
                        i_polyA.Add(sharedIndex[i]);
                        c_polyA.Add(colors[i]);
                    }
                    else
                    {
                        v_polyB.Add(verts[i]);
                        v_polyB_2d.Add(plane[i]);
                        u_polyB.Add(uvs[i]);
                        i_polyB.Add(sharedIndex[i]);
                        c_polyB.Add(colors[i]);
                    }
                }
            }

            if (!splitSelection.aIsVertex)
            {
                v_polyA.Add(splitPointA_3d);
                v_polyA_2d.Add(splitPointA_2d);
                u_polyA.Add(splitPointA_uv);
                i_polyA.Add(-1);
                c_polyA.Add(splitSelection.colorA);

                v_polyB.Add(splitPointA_3d);
                v_polyB_2d.Add(splitPointA_2d);
                u_polyB.Add(splitPointA_uv);
                i_polyB.Add(-1);                //	neg 1 because it's a new vertex point
                c_polyB.Add(splitSelection.colorA);

                nedgeA.Add(v_polyA.Count);
                nedgeB.Add(v_polyB.Count);
            }

            // PLACE
            if (!splitSelection.bIsVertex)
            {
                v_polyA.Add(splitPointB_3d);
                v_polyA_2d.Add(splitPointB_2d);
                u_polyA.Add(splitPointB_uv);
                i_polyA.Add(-1);
                c_polyB.Add(splitSelection.colorB);

                v_polyB.Add(splitPointB_3d);
                v_polyB_2d.Add(splitPointB_2d);
                u_polyB.Add(splitPointB_uv);
                i_polyB.Add(-1);                //	neg 1 because it's a new vertex point
                c_polyB.Add(splitSelection.colorB);

                nedgeA.Add(v_polyA.Count);
                nedgeB.Add(v_polyB.Count);
            }

            if (v_polyA_2d.Count < 3 || v_polyB_2d.Count < 3)
            {
                splitFaces         = null;
                splitVertices      = null;
                splitSharedIndices = null;
                return(false);
            }

            // triangulate new polygons
            int[] t_polyA = Delaunay.Triangulate(v_polyA_2d).ToIntArray();
            int[] t_polyB = Delaunay.Triangulate(v_polyB_2d).ToIntArray();

            if (t_polyA.Length < 3 || t_polyB.Length < 3)
            {
                return(false);
            }

            // figure out the face normals for the new faces and check to make sure they match the original face
            Vector2[] pln = pb_Math.PlanarProject(pb.GetVertices(face.indices), projAxis);

            Vector3 nrm  = Vector3.Cross(pln[2] - pln[0], pln[1] - pln[0]);
            Vector3 nrmA = Vector3.Cross(v_polyA_2d[t_polyA[2]] - v_polyA_2d[t_polyA[0]], v_polyA_2d[t_polyA[1]] - v_polyA_2d[t_polyA[0]]);
            Vector3 nrmB = Vector3.Cross(v_polyB_2d[t_polyB[2]] - v_polyB_2d[t_polyB[0]], v_polyB_2d[t_polyB[1]] - v_polyB_2d[t_polyB[0]]);

            if (Vector3.Dot(nrm, nrmA) < 0)
            {
                System.Array.Reverse(t_polyA);
            }
            if (Vector3.Dot(nrm, nrmB) < 0)
            {
                System.Array.Reverse(t_polyB);
            }

            // triangles, material, pb_UV, smoothing group, shared index
            pb_Face faceA = new pb_Face(t_polyA, face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, face.elementGroup, face.manualUV);
            pb_Face faceB = new pb_Face(t_polyB, face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, face.elementGroup, face.manualUV);

            splitFaces = new pb_Face[2] {
                faceA, faceB
            };
            splitVertices      = new Vector3[2][] { v_polyA.ToArray(), v_polyB.ToArray() };
            splitColors        = new Color[2][] { c_polyA.ToArray(), c_polyB.ToArray() };
            splitUVs           = new Vector2[2][] { u_polyA.ToArray(), u_polyB.ToArray() };
            splitSharedIndices = new int[2][] { i_polyA.ToArray(), i_polyB.ToArray() };

            return(true);
        }
Пример #9
0
        /**
         *	Inserts a split from each selected vertex to the center of the face
         */
        private static bool PokeFace_Internal(pb_Object pb, pb_Face face, int[] indices_nonFaceSpecific,
                                              out Vector3 pokedVertex,
                                              out pb_Face[] splitFaces,
                                              out Vector3[][] splitVertices,
                                              out Color[][] splitColors,
                                              out Vector2[][] splitUVs,
                                              out int[][] splitSharedIndices)
        {
            pokedVertex        = Vector3.zero;
            splitFaces         = null;
            splitVertices      = null;
            splitColors        = null;
            splitUVs           = null;
            splitSharedIndices = null;

            pb_IntArray[] sharedIndices = pb.sharedIndices;

            ///** Sort index array such that it only uses indices local to the passed face
            int[] dist_indices = new int[indices_nonFaceSpecific.Length];
            int[] dist_ind_si  = new int[face.distinctIndices.Length];

            // figure out sharedIndices index of distinct Indices
            for (int i = 0; i < face.distinctIndices.Length; i++)
            {
                dist_ind_si[i] = sharedIndices.IndexOf(face.distinctIndices[i]);
            }

            // now do the same for non-face specific indices, assigning matching groups

            ///** Sort index array such that it only uses indices local to the passed face
            for (int i = 0; i < dist_indices.Length; i++)
            {
                int ind = System.Array.IndexOf(dist_ind_si, sharedIndices.IndexOf(indices_nonFaceSpecific[i]));
                if (ind < 0)
                {
                    return(false);
                }

                dist_indices[i] = face.distinctIndices[ind];
            }

            int[] indices = dist_indices.Distinct().ToArray();

            // throw out splits with less than 2 vertices, or splits composed
            // of a single edge
            switch (indices.Length)
            {
            case 0:
            case 1:
                return(false);

            case 2:
                if (System.Array.IndexOf(face.edges, new pb_Edge(indices[0], indices[1])) > -1)
                {
                    return(false);
                }
                break;

            default:
                break;
            }

            // end triangle sorting

            /**
             *	The general idea here is to project the face into 2d space,
             *	split the 2d points into groups based on the intersecting lines,
             *	then triangulate those groups.  once the groups have been
             *	triangulated, rebuild the 3d vertices using the new groups
             *	(building new verts for seams).
             *
             *	Think like you're cutting a pie... but first the pie is a basketball,
             *	then a pie, then a basketball again.  I'm on a horse.
             */

            Vector3[] verts  = pb.GetVertices(face.distinctIndices);
            Vector2[] uvs    = pb.GetUVs(face.distinctIndices);
            Color[]   colors = pbUtil.ValuesWithIndices(pb.colors, face.distinctIndices);

            Vector2 cenUV = pb_Bounds2D.Center(uvs);
            Vector3 cen3d = pb_Math.Average(verts);

            pokedVertex = cen3d;
            Vector3 nrm      = pb_Math.Normal(pb.GetVertices(face.indices));
            Color   cenColor = pb_Math.Average(colors);

            // this should be cleaned up
            Vector2[] plane    = pb_Math.PlanarProject(verts, nrm);
            Vector2[] indPlane = pb_Math.PlanarProject(pb.GetVertices(indices), nrm);
            Vector2   cen2d    = pb_Math.PlanarProject(new Vector3[1] {
                cen3d
            }, nrm)[0];

            // Get the directions from which to segment this face
            Vector2[] dividers = new Vector2[indices.Length];
            for (int i = 0; i < indices.Length; i++)
            {
                dividers[i] = (indPlane[i] - cen2d).normalized;
            }

            List <Vector2>[] quadrants2d    = new List <Vector2> [indices.Length];
            List <Vector3>[] quadrants3d    = new List <Vector3> [indices.Length];
            List <Vector2>[] quadrantsUV_2d = new List <Vector2> [indices.Length];
            List <Color>[]   quadrantsCol   = new List <Color> [indices.Length];

            List <int>[] sharedIndex = new List <int> [indices.Length];

            for (int i = 0; i < quadrants2d.Length; i++)
            {
                quadrants2d[i] = new List <Vector2>(1)
                {
                    cen2d
                };
                quadrants3d[i] = new List <Vector3>(1)
                {
                    cen3d
                };
                quadrantsUV_2d[i] = new List <Vector2>(1)
                {
                    cenUV
                };
                quadrantsCol[i] = new List <Color>(1)
                {
                    cenColor
                };

                sharedIndex[i] = new List <int>(1)
                {
                    -2
                };                                                              // any negative value less than -1 will be treated as a new group
            }

            for (int i = 0; i < face.distinctIndices.Length; i++)
            {
                // if this index is a divider, it needs to belong to the leftmost and
                // rightmost quadrant
                int indexInPokeVerts = System.Array.IndexOf(indices, face.distinctIndices[i]);
                int ignore           = -1;
                if (indexInPokeVerts > -1)
                {
                    // Add vert to this quadrant
                    quadrants2d[indexInPokeVerts].Add(plane[i]);
                    quadrants3d[indexInPokeVerts].Add(verts[i]);
                    quadrantsUV_2d[indexInPokeVerts].Add(uvs[i]);
                    quadrantsCol[indexInPokeVerts].Add(colors[i]);

                    sharedIndex[indexInPokeVerts].Add(pb.sharedIndices.IndexOf(face.distinctIndices[i]));

                    // And also the one closest counter clockwise
                    ignore = indexInPokeVerts;
                }

                Vector2 dir = (plane[i] - cen2d).normalized;            // plane corresponds to distinctIndices
                float   largestClockwiseDistance = 0f;
                int     quad = -1;
                for (int j = 0; j < dividers.Length; j++)
                {
                    if (j == ignore)
                    {
                        continue;                               // this is a dividing vertex - ignore
                    }
                    float dist = Vector2.Angle(dividers[j], dir);
                    if (Vector2.Dot(pb_Math.Perpendicular(dividers[j]), dir) < 0f)
                    {
                        dist = 360f - dist;
                    }

                    if (dist > largestClockwiseDistance)
                    {
                        largestClockwiseDistance = dist;
                        quad = j;
                    }
                }

                quadrants2d[quad].Add(plane[i]);
                quadrants3d[quad].Add(verts[i]);
                quadrantsUV_2d[quad].Add(uvs[i]);
                quadrantsCol[quad].Add(colors[i]);

                sharedIndex[quad].Add(pb.sharedIndices.IndexOf(face.distinctIndices[i]));
            }

            int len = quadrants2d.Length;

            // Triangulate
            int[][] tris = new int[len][];
            for (int i = 0; i < len; i++)
            {
                try {
                    tris[i] = Delaunay.Triangulate(quadrants2d[i]).ToIntArray();

                    if (tris[i] == null || tris[i].Length < 3)
                    {
                        Debug.Log("Fail triangulation");
                        return(false);
                    }
                } catch (System.Exception error) {
                    Debug.LogError("PokeFace internal failed triangulation. Bail!\n" + error);
                    return(false);
                }

                // todo - check that face normal is correct
            }

            splitFaces         = new pb_Face[len];
            splitVertices      = new Vector3[len][];
            splitColors        = new Color[len][];
            splitUVs           = new Vector2[len][];
            splitSharedIndices = new int[len][];

            for (int i = 0; i < len; i++)
            {
                // triangles, material, pb_UV, smoothing group, shared index
                splitFaces[i]    = new pb_Face(tris[i], face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, -1, face.manualUV);
                splitVertices[i] = quadrants3d[i].ToArray();
                splitColors[i]   = quadrantsCol[i].ToArray();
                splitUVs[i]      = quadrantsUV_2d[i].ToArray();

                splitSharedIndices[i] = sharedIndex[i].ToArray();
            }

            return(true);
        }
Пример #10
0
        public Maze(FPseudoRandom random,
                    FVec3 scale, FVec3 offset, int row, int col,
                    int startIndex, int endIndex, FVec2 startPointPlace)
        {
            this.startPointPlace = startPointPlace;
            if (this.row < ( int )this.startPointPlace.y + 3 ||
                this.col < ( int )this.startPointPlace.x + 3)
            {
                throw new Exception("The row or col invaild");
            }

            this.scale  = scale;
            this.offset = offset;
            this.row    = row;
            this.col    = col;

            this._localToWorld = FMat4.FromTRS(this.offset, FQuat.identity, this.scale);
            this._worldToLocal = FMat4.NonhomogeneousInverse(this._localToWorld);

            //创建二维图
            Graph2D graph2 = this.CreateFullDigraph(random);

            //创建格子
            this.CreateTiles(graph2);

            //是否随机起点和终点
            this.startIndex = startIndex < 0 ? this.RandomIndexWithinBorder(random) : startIndex;
            if (endIndex < 0)
            {
                int[] candidate = new int[5];
                for (int i = 0; i < 5; i++)
                {
                    candidate[i] = this.RandomIndexWithinBorder(random);
                }
                endIndex = this.GetFarthestToStartIndex(this.startIndex, candidate);
            }
            this.endIndex = endIndex;

            //初始化起点范围
            HashSet <int> walkablesHs = new HashSet <int>();

            this.SetStart(graph2, this.startIndex, walkablesHs);

            //创建起点和终点
            int[]            coord       = graph2.IndexToCoord(this.startIndex);
            Delaunay.DVertex startVertex = new Delaunay.DVertex(coord[0], coord[1]);
            coord = graph2.IndexToCoord(this.endIndex);
            Delaunay.DVertex endVertex = new Delaunay.DVertex(coord[0], coord[1]);
            //创建外圆周附近的顶点
            List <Delaunay.DVertex> vertices1 = this.GenVertices(24, 1f, 0.8f, 24, random);
            //创建内圆周附近的顶点
            List <Delaunay.DVertex> vertices2 = this.GenVertices(12, 0.2f, 0.6f, 12, random);
            //合并所有顶点
            List <Delaunay.DVertex> vertices = new List <Delaunay.DVertex> {
                startVertex, endVertex
            };

            vertices.AddRange(vertices1);
            vertices.AddRange(vertices2);

            //点集合的三角化
            List <Delaunay.DTriangle> triangles = Delaunay.Triangulate(vertices);

            //从三角形集合创建图
            GraphBase graph = Tools.TrianglesToGraph(triangles, random.NextFloat);
            //Prim算法创建最小生成树
            List <GraphEdge> edges = GraphSearcher.PrimSearch(graph, triangles[0].v0);

            //每条边用A*算法生成路径
            int count = edges.Count;

            for (int i = 0; i < count; i++)
            {
                GraphEdge        edge = edges[i];
                Delaunay.DVertex v0   = vertices[edge.from];
                Delaunay.DVertex v1   = vertices[edge.to];
                int[]            path = GraphSearcher.AStarSearch(graph2, graph2.CoordToIndex(( int )v0.x, ( int )v0.y),
                                                                  graph2.CoordToIndex(( int )v1.x, ( int )v1.y));
                this.SetPathWalkable(path, walkablesHs);

                //把顶点扩展成房间
                if (i == 0)
                {
                    this.SetIndexToWalkable(graph2, ( int )v0.x, ( int )v0.y, random.Next(1, 3), random.Next(1, 3), walkablesHs);
                }
                this.SetIndexToWalkable(graph2, ( int )v1.x, ( int )v1.y, random.Next(1, 3), random.Next(1, 3), walkablesHs);
            }

            this.walkables = walkablesHs.ToArray();
        }
Пример #11
0
        /**
         *	Given a face and a point, this will add a vertex to the pb_Object and retriangulate the face.
         */
        public static bool AppendVerticesToFace(this pb_Object pb, pb_Face face, Vector3[] points, Color[] addColors, out pb_Face newFace)
        {
            if (!face.IsValid())
            {
                newFace = face;
                return(false);
            }

            // First order of business - project face to 2d
            int[]     distinctIndices = face.distinctIndices;
            Vector3[] verts           = pb.GetVertices(distinctIndices);
            Color[]   cols            = pbUtil.ValuesWithIndices(pb.colors, distinctIndices);
            Vector2[] uvs             = new Vector2[distinctIndices.Length + points.Length];
            System.Array.Copy(pb.GetUVs(distinctIndices), 0, uvs, 0, distinctIndices.Length);

            // Add the new point
            Vector3[] t_verts = new Vector3[verts.Length + points.Length];
            System.Array.Copy(verts, 0, t_verts, 0, verts.Length);
            System.Array.Copy(points, 0, t_verts, verts.Length, points.Length);
            verts = t_verts;

            // Add the new color
            Color[] t_col = new Color[cols.Length + addColors.Length];
            System.Array.Copy(cols, 0, t_col, 0, cols.Length);
            System.Array.Copy(addColors, 0, t_col, cols.Length, addColors.Length);
            cols = t_col;

            // Get the face normal before modifying the vertex array
            Vector3 nrm      = pb_Math.Normal(pb.GetVertices(face.indices));
            Vector3 projAxis = pb_Math.ProjectionAxisToVector(pb_Math.VectorToProjectionAxis(nrm));

            // Project
            List <Vector2> plane = new List <Vector2>(pb_Math.PlanarProject(verts, projAxis));

            // Save the sharedIndices index for each distinct vertex
            pb_IntArray[] sharedIndices = pb.sharedIndices;
            int[]         sharedIndex   = new int[distinctIndices.Length + points.Length];
            for (int i = 0; i < distinctIndices.Length; i++)
            {
                sharedIndex[i] = sharedIndices.IndexOf(distinctIndices[i]);
            }

            for (int i = distinctIndices.Length; i < distinctIndices.Length + points.Length; i++)
            {
                sharedIndex[i] = -1;            // add the new vertex to it's own sharedIndex
            }
            // Triangulate the face with the new point appended
            int[] tris = Delaunay.Triangulate(plane).ToIntArray();

            // Check to make sure the triangulated face is facing the same direction, and flip if not
            Vector3 del = Vector3.Cross(verts[tris[2]] - verts[tris[0]], verts[tris[1]] - verts[tris[0]]).normalized;

            if (Vector3.Dot(nrm, del) > 0)
            {
                System.Array.Reverse(tris);
            }

            // Build the new face
            pb_Face triangulated_face = new pb_Face(tris, face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, -1, face.manualUV);

            /**
             * Attempt to figure out where the new UV point(s) should go (if auto uv'ed face)
             */
            if (triangulated_face.manualUV)
            {
                for (int n = distinctIndices.Length; n < uvs.Length; n++)
                {
                    // these are the two vertices that are split by the new vertex
                    int[] adjacent_vertex = System.Array.FindAll(triangulated_face.edges, x => x.Contains(n)).Select(x => x.x != n ? x.x : x.y).ToArray();

                    if (adjacent_vertex.Length == 2)
                    {
                        uvs[n] = (uvs[adjacent_vertex[0]] + uvs[adjacent_vertex[1]]) / 2f;
                    }
                    else
                    {
                        Debug.LogWarning("Failed to find appropriate UV coordinate for new vertex point.  Setting face to AutoUV.");
                        triangulated_face.manualUV = false;
                    }
                }
            }

            // Compose new face
            newFace = pb.AppendFace(verts, cols, uvs, triangulated_face, sharedIndex);

            // And delete the old
            pb.DeleteFace(face);

            return(true);
        }
Пример #12
0
 /// <summary>
 /// Constructs the Delaunay triangulation of a set of points.
 /// </summary>
 public static void Triangulate(this IEnumerable <Vector> points, List <Triangle> triangles)
 {
     Delaunay.Triangulate(points, triangles);
 }