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); } }
public Triangle[] Delaunay() { Vertex[] apexs = GetAllDelaunayApex(); Delaunay delaunay = new Delaunay(); delaunay.Triangulate(apexs); //为三角形添加颜色 var tris = delaunay.Triangles; SampleColor(tris); return(tris.ToArray()); }
// 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; } } } } } }
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; } }
/** * 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); }
/** * 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); }
/** * 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); }
/** * 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); }
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(); }
/** * 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); }
/// <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); }