private TerrainParticles GenerateParticles(PSPolygon shape) { var center = shape.Bounds.center; var coords = new List <Vector2>(); Vector2 coord; var xMin = shape.Bounds.xMin; var xMax = shape.Bounds.xMax; var yMin = shape.Bounds.yMin; var yMax = shape.Bounds.yMax; for (float x = xMin; x < xMax; x += 0.1f) { for (float y = yMin; y < yMax; y += 0.1f) { coord = new Vector2(x, y); if (shape.PointInPolygon(coord)) { coords.Add(coord); } } } if (coords.Count > maxParticles) { int everyNth = coords.Count / maxParticles + 1; coords = coords.Where((p, i) => i % everyNth == 0).ToList(); } var mainTexUV = coords.Select(c => terrainMesh.getMainTexUV(c, doNotWrapUV)); var overlayTexUV = coords.Select(c => terrainMesh.getOverlayTexUV(c, doNotWrapUV, floorEdges)); var colors = coords.Select(c => terrainMesh.terrainTintColor(c, doNotWrapUV)); return(new TerrainParticles(coords.ToArray(), mainTexUV.ToArray(), overlayTexUV.ToArray(), colors.ToArray(), center)); }
public static List <PSPolygon> ContourPolygons(List <Vector2> vertices, List <int> triangles) { Dictionary <string, Edge> edges = new Dictionary <string, Edge>(); for (int i = 0; i < triangles.Count; i += 3) { for (int e = 0; e < 3; e++) { Edge edge = new Edge(triangles[i + e], triangles[i + e + 1 > i + 2 ? i : i + e + 1]); if (edges.ContainsKey(edge.key)) { edges.Remove(edge.key); } else { edges.Add(edge.key, edge); } } } var lookup = edges.Values.ToLookup(e => e.v0); var polygons = new List <PSPolygon>(); if (edges.Count == 0) { return(polygons); } Edge startEdge = edges.Values.First(); Edge nextEdge = startEdge; List <int> colliderPath = new List <int>(); while (true) { colliderPath.Add(nextEdge.v0); var removed = edges.Remove(nextEdge.key); nextEdge = SelectEdge(vertices, nextEdge, lookup[nextEdge.v1]); if (nextEdge.key == startEdge.key) { var polygon = new PSPolygon(colliderPath.Select(index => vertices[index])); polygons.Add(polygon); colliderPath.Clear(); if (edges.Count > 0) { startEdge = edges.Values.First(); nextEdge = startEdge; continue; } break; } } return(polygons); }
private void UpdateCaveBackground(Vector2[][] segments) { var outerSteps = Mathf.FloorToInt(outerRadius * Mathf.PI * 2 / 4); var outerPolygon = Enumerable.Range(0, outerSteps).Select(i => { var angle = 2f * Mathf.PI * i / outerSteps; return(new Vector2(Mathf.Sin(angle), Mathf.Cos(angle)) * outerRadius); }); var innerSteps = Mathf.FloorToInt(innerRadius * Mathf.PI * 2 / 4); var innerPolygon = Enumerable.Range(0, innerSteps).Select(i => { var angle = -2f * Mathf.PI * i / innerSteps; return(new Vector2(Mathf.Sin(angle), Mathf.Cos(angle)) * innerRadius); }); var area = new List <IEnumerable <Vector2> >(2); area.Add(outerPolygon); area.Add(innerPolygon); var constraint = new ConstraintOptions(); constraint.ConformingDelaunay = true; var quality = new QualityOptions(); quality.MaximumArea = 10; var data = segments.AsParallel().Select(segment => { var segmentPolygon = new PSPolygon(segment); var doNotWrapUV = segmentPolygon.Bounds.center.x < 0 && segmentPolygon.Bounds.center.y < 0; var poly = new Polygon(); foreach (var polygon in PSClipperHelper.intersection(area, segment)) { poly.Add(createContour(polygon)); } var imesh = poly.Triangulate(constraint, quality); var vertices = new List <Vector2>(); var triangles = new List <int>(); getTriangles(imesh, ref vertices, ref triangles); var uv = vertices.Select(v => getUV(v, doNotWrapUV)).ToList(); var colors = vertices.Select(v => (Color32)backgroundTintColor(v, doNotWrapUV)).ToList(); return(new { vertices, triangles, uv, colors }); }).ToList(); var currentIndex = 0; var tris = new List <int>(); foreach (var d in data) { tris.AddRange(d.triangles.Select(i => currentIndex + i)); currentIndex += d.vertices.Count; } UpdateMesh( caveBackground, data.SelectMany(d => d.vertices).Select(v => (Vector3)v), data.SelectMany(d => d.uv), null, data.SelectMany(d => d.colors), tris); }
private GameObject GenerateFragment(PSPolygon polygon) { TerrainPiece piece = Instantiate(terrainPieceTemplate, gameObject.transform.position, gameObject.transform.rotation); var poly = new Polygon(); poly.Add(TerrainMesh.createContour(polygon.points)); var quality = new QualityOptions(); quality.MinimumAngle = 36; quality.MaximumAngle = 91; var imesh = poly.Triangulate(quality); List <Vector2> vertices = new List <Vector2>(); List <int> triangles = new List <int>(); getTriangles(imesh, ref vertices, ref triangles); var polygonBoundsCenter = polygon.Bounds.center; var doNotWrapUV = polygonBoundsCenter.x < 0 && polygonBoundsCenter.y < 0; var floorEdges = getFloorEdges(polygon); var uvs = vertices.Select(v => getUV(v, doNotWrapUV)).ToArray(); var uv2s = vertices.Select(v => getUV2(v, doNotWrapUV, floorEdges)).ToArray(); UpdateMesh( piece.GetComponent <MeshFilter>(), vertices.Select(v => (Vector3)v), uvs, uv2s, vertices.Select(p => (Color32)terrainTintColor(p, doNotWrapUV)), triangles); UpdateMesh( piece.background, vertices.Select(v => (Vector3)v), uvs, uv2s, vertices.Select(p => (Color32)backgroundTintColor(p, doNotWrapUV)), triangles); PolygonCollider2D collider = piece.gameObject.AddComponent <PolygonCollider2D>(); collider.SetPath(0, polygon.points); piece.terrainMesh = this; piece.doNotWrapUV = doNotWrapUV; piece.floorEdges = floorEdges; piece.gameObject.SetActive(true); return(piece.gameObject); }
private void DrawPolygon(PSPolygon polygon, Vector2 offset) { for (int i = 0; i < polygon.points.Length; i++) { if (i + 1 == polygon.points.Length) { Gizmos.DrawLine(polygon.points[i] + offset, polygon.points[0] + offset); } else { Gizmos.DrawLine(polygon.points[i] + offset, polygon.points[i + 1] + offset); } } }
private static List <PSEdge> getCeilingEdges(PSPolygon polygon, float innerRadius) { var ceilingEdges = new List <PSEdge>(); Vector2 previous = polygon.points.Last(); bool previousIsCeiling = isCeilingPoint(previous, polygon, innerRadius); bool currentIsCeiling; foreach (var p in polygon.points) { currentIsCeiling = isCeilingPoint(p, polygon, innerRadius); if ((currentIsCeiling || previousIsCeiling) && Vector3.Cross(previous, p).sqrMagnitude > 0) { ceilingEdges.Add(new PSEdge(previous, p)); } previous = p; previousIsCeiling = currentIsCeiling; } return(ceilingEdges); }
private static List <PSEdge> getFloorEdges(PSPolygon polygon) { var floorEdges = new List <PSEdge>(); Vector2 previous = polygon.points.Last(); bool previousIsFloor = isFloorPoint(previous, polygon); bool currentIsFloor; foreach (var p in polygon.points) { currentIsFloor = isFloorPoint(p, polygon); if ((currentIsFloor || previousIsFloor) && Vector3.Cross(previous, p).sqrMagnitude > 0) { floorEdges.Add(new PSEdge(previous, p)); } previous = p; previousIsFloor = currentIsFloor; } return(floorEdges); }
private void GenerateTerrainTriangles(List <Vector2> points, out List <Vector2> vertices, out List <int> triangles) { var imesh = new GenericMesher().Triangulate(points.Select(toVertex).ToList()); var idToIndex = new Dictionary <int, int>(); vertices = new List <Vector2>(); triangles = new List <int>(); foreach (var triangle in imesh.Triangles) { if (!caveSystem.insideCave(PSPolygon.GetCenter(triangle.vertices.Select(toVector2).ToList()))) { foreach (var v in triangle.vertices.Reverse()) { if (!idToIndex.ContainsKey(v.ID)) { idToIndex.Add(v.ID, vertices.Count); vertices.Add(toVector2(v)); } triangles.Add(idToIndex[v.ID]); } } } }
private static bool isCeilingPoint(Vector2 point, PSPolygon polygon, float innerRadius) { return(point.magnitude > innerRadius + 0.005f && polygon.PointInPolygon(point + (point.normalized * 0.005f))); }
private static bool isFloorPoint(Vector2 point, PSPolygon polygon) { return(polygon.PointInPolygon(point + (point.normalized * -0.005f))); }
public static List <PSPolygon> difference(PSPolygon subject, PSPolygon clip) { return(PSClipperHelper.difference(subject.points, clip.points).Select(p => new PSPolygon(p)).ToList()); }