/* * e.v1 _________________ e.v5 * \ | | | / * m.v1\__|___|___|__/m.v5 * \ | | | / * \|___|___|/ * cL c cR * e.v1 ~ e.v5 平均分成4分 每份是1/4 * m/e = 3/4,所以 m.v1 ~ m.v5 是1/6,1/4,1/4,1/6 */ /// <summary> /// 河道三角化 /// </summary> /// <param name="cell"></param> /// <param name="direction"></param> /// <param name="center"></param> /// <param name="edge"></param> private void TriangulateWithRiver(HexCell cell, HexDirectionEnum direction, Vector3 center, EdgeVertices edge) { Vector3 centerL; Vector3 centerR; if (cell.HasRiverThroughEdge(direction.Opposite())) { centerL = center + HexMetrics.GetFirstSolidCorner(direction.Previous()) * 1 / 4f; centerR = center + HexMetrics.GetSecondSolidCorner(direction.Next()) * 1 / 4f; } else if (cell.HasRiverThroughEdge(direction.Previous())) { centerL = Vector3.Lerp(center, edge.v1, 2 / 3f); centerR = center; } else if (cell.HasRiverThroughEdge(direction.Next())) { centerL = center; centerR = Vector3.Lerp(center, edge.v5, 2 / 3f); } else if (cell.HasRiverThroughEdge(direction.Next(2))) { centerL = center; centerR = center + HexMetrics.GetSolidEdgeMiddle(direction.Next()) * (0.5f * HexMetrics.innerToOuter); } else { centerL = center + HexMetrics.GetSolidEdgeMiddle(direction.Previous()) * (0.5f * HexMetrics.innerToOuter); centerR = center; } center = Vector3.Lerp(centerL, centerR, 0.5f); EdgeVertices m = new EdgeVertices(Vector3.Lerp(centerL, edge.v1, 0.5f), Vector3.Lerp(centerR, edge.v5, 0.5f), 1 / 6f); m.v3.y = center.y = edge.v3.y; TriangulateEdgeStrip(m, weights1, cell.Index, edge, weights1, cell.Index); AddTerrainPerturTriangle(centerL, m.v1, m.v2); AddTerrainQuad(centerL, center, m.v2, m.v3); AddTerrainQuad(center, centerR, m.v3, m.v4); AddTerrainPerturTriangle(centerR, m.v4, m.v5); Vector3 indices; indices.x = indices.y = indices.z = cell.Index; terrain.AddTriangleCellData(indices, weights1); terrain.AddQuadCellData(indices, weights1); terrain.AddQuadCellData(indices, weights1); terrain.AddTriangleCellData(indices, weights1); bool reversed = cell.InComingRive == direction; TriangulateRiverQuad(centerL, centerR, m.v2, m.v4, cell.RiverSurfaceHight, 0.4f, reversed, indices); TriangulateRiverQuad(m.v2, m.v4, edge.v2, edge.v4, cell.RiverSurfaceHight, 0.6f, reversed, indices); }
private void TriangulateAdjacentToRiver(HexCell cell, HexDirectionEnum direction, Vector3 center, EdgeVertices edge) { if (cell.HasRoads) { TriangulateRoadAdjacentToRiver(direction, cell, center, edge); } if (cell.HasRiverThroughEdge(direction.Next())) { if (cell.HasRiverThroughEdge(direction.Previous())) { center += HexMetrics.GetSolidEdgeMiddle(direction) * (HexMetrics.innerToOuter * 0.5f); } else if (cell.HasRiverThroughEdge(direction.Previous(2))) { center += HexMetrics.GetFirstSolidCorner(direction) * 0.25f; } } else if (cell.HasRiverThroughEdge(direction.Previous()) && cell.HasRiverThroughEdge(direction.Next(2))) { center += HexMetrics.GetSecondSolidCorner(direction) * 0.25f; } EdgeVertices m = new EdgeVertices(Vector3.Lerp(center, edge.v1, 0.5f), Vector3.Lerp(center, edge.v5, 0.5f)); TriangulateEdgeStrip(m, weights1, cell.Index, edge, weights1, cell.Index); TriangulateEdgeFan(center, m, cell.Index); }
//仅处理无临边的情况 private void NoNeighborConnection(HexDirectionEnum direction, HexCell cell, EdgeVertices edge) { Vector3 center = cell.Position; Vector3 bridge = HexMetrics.GetOneBridge(direction); Vector3 v3 = edge.v1 + bridge; Vector3 v4 = edge.v5 + bridge; Vector3 v5 = center + HexMetrics.GetFirstCorner(direction); Vector3 v6 = center + HexMetrics.GetSecondCorner(direction); HexCell prevNeighbor = cell.GetNeighbor(direction.Previous()); HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); v6.y = v5.y = v4.y = v3.y = 0; EdgeVertices edge2 = new EdgeVertices(v5, v6); if (nextNeighbor == null && prevNeighbor != null) { edge2 = new EdgeVertices(v3, v6); HexCell noneCell = new GameObject().AddComponent <HexCell>(); noneCell.Index = cell.Index; TriangulateCorner(edge.v1, cell, v5, prevNeighbor, v3, noneCell); DestroyObject(noneCell.gameObject); } if (cell.Elevation == HexMetrics.elevationDiffer) { TriangulateEdgeTerraces(edge, cell, edge2, cell, cell.HasRoadThroughEdge(direction)); } else { TriangulateEdgeStrip(edge, weights1, cell.Index, edge2, weights1, cell.Index, cell.HasRoadThroughEdge(direction)); } }
//仅处理无临边的情况 private void NoNeighborConnection(HexDirectionEnum direction, HexCell cell, Vector3 v1, Vector3 v2) { Vector3 center = cell.center; Vector3 bridge = HexMetrics.GetOneBridge(direction); Vector3 v3 = v1 + bridge; Vector3 v4 = v2 + bridge; Vector3 v5 = center + HexMetrics.GetFirstCorner(direction); Vector3 v6 = center + HexMetrics.GetSecondConrner(direction); HexCell prevNeighbor = cell.GetNeighbor(direction.Previous()); HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); Vector3 v7 = v5; Vector3 v8 = v6; if (nextNeighbor == null && prevNeighbor != null) { v7 = v3; v8 = v6; Color firstColor = (cell.color + cell.color + prevNeighbor.color) / 3f; AddTriangle(v1, v5, v3); AddTriangleColor(cell.color, firstColor, cell.color); } AddQuad(v1, v2, v7, v8); AddQuadColor(cell.color); }
private void RightTrangulateConnection(HexDirectionEnum direction, HexCell cell, Vector3 v1, Vector3 v2) { HexCell neighbor = cell.GetNeighbor(direction); if (neighbor == null) { NoNeighborConnection(direction, cell, v1, v2); return; } Vector3 bridge = HexMetrics.GetTwoBridge(direction); Vector3 v3 = v1 + bridge; Vector3 v4 = v2 + bridge; AddQuad(v1, v2, v3, v4); AddQuadColor(cell.color, neighbor.color); HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); if (nextNeighbor != null) { AddTriangle(v2, v4, v2 + HexMetrics.GetTwoBridge(direction.Next())); AddTriangleColor(cell.color, neighbor.color, nextNeighbor.color); } else { //绘制缺失的小三角 AddTriangle(v2, v4, cell.center + HexMetrics.GetSecondConrner(direction)); AddTriangleColor(cell.color, neighbor.color, (cell.color + neighbor.color) * 0.5f); } //绘制缺失的小三角 HexCell prevNeighbor = cell.GetNeighbor(direction.Previous()); if (prevNeighbor == null) { AddTriangle(v1, cell.center + HexMetrics.GetFirstCorner(direction), v3); AddTriangleColor(cell.color, (cell.color + cell.color + neighbor.color) / 3f, neighbor.color); } }
private void TriangulateOpenWater(HexDirectionEnum direction, HexCell cell, HexCell neighbor, Vector3 center) { Vector3 c1 = center + HexMetrics.GetWaterFirstCorner(direction); Vector3 c2 = center + HexMetrics.GetWaterSecondCorner(direction); water.AddPerturTriangle(center, c1, c2); Vector3 indices; indices.x = indices.y = indices.z = cell.Index; water.AddTriangleCellData(indices, weights1); if (neighbor != null && DirectionOnRight(direction)) { Vector3 bridge = HexMetrics.GetWaterBridge(direction); Vector3 e1 = c1 + bridge; Vector3 e2 = c2 + bridge; water.AddPerturQuad(c1, c2, e1, e2); indices.y = neighbor.Index; water.AddQuadCellData(indices, weights1, weights2); if (direction == HexDirectionEnum.TopRight || direction == HexDirectionEnum.Right) { HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); if (nextNeighbor == null || !nextNeighbor.IsUnderWater) { return; } water.AddPerturTriangle(c2, e2, c2 + HexMetrics.GetWaterBridge(direction.Next())); indices.z = nextNeighbor.Index; water.AddTriangleCellData(indices, weights1, weights2, weights3); } } }
private Vector2 GetRoadInterpolators(HexDirectionEnum direction, HexCell cell) { Vector2 interpolators = new Vector2(); if (cell.HasRoadThroughEdge(direction)) { interpolators.x = interpolators.y = 0.5f; } else { interpolators.x = cell.HasRoadThroughEdge(direction.Previous( )) ? 0.5f : 0.25f; interpolators.y = cell.HasRoadThroughEdge(direction.Next( )) ? 0.5f : 0.25f; } return(interpolators); }
private int CreateRiver(HexCell origin) { int length = 1; HexCell cell = origin; HexDirectionEnum direction = HexDirectionEnum.BottomLeft; while (!cell.IsUnderWater) { int minNeighbirElevation = int.MaxValue; flowDirections.Clear(); for (HexDirectionEnum d = 0; d < HexDirectionEnum.Length; d++) { HexCell neighbor = cell.GetNeighbor(d); if (!neighbor) { continue; } if (neighbor.Elevation < minNeighbirElevation) { minNeighbirElevation = neighbor.Elevation; } if (neighbor == origin || neighbor.HasInComingRiver) { continue; } int delta = neighbor.Elevation - cell.Elevation; if (delta > 0) { continue; } if (neighbor.HasOutGoingRive) { cell.SetOutGoingRiver(d); return(length); } if (neighbor.IsUnderWater) { cell.SetOutGoingRiver(d); return(length); } if (delta <= 0) { flowDirections.Add(d); flowDirections.Add(d); flowDirections.Add(d); } if (length == 1 || (d != direction.Next(2) && d != direction.Previous(2))) { flowDirections.Add(d); } flowDirections.Add(d); } if (flowDirections.Count <= 0) { if (length == 1) { return(0); } if (minNeighbirElevation >= cell.Elevation) { cell.WaterLevel = minNeighbirElevation; if (minNeighbirElevation == cell.Elevation) { cell.Elevation = minNeighbirElevation - 1; } } break; } direction = flowDirections[Random.Range(0, flowDirections.Count)]; cell.SetOutGoingRiver(direction); length += 1; if (minNeighbirElevation >= cell.Elevation && Random.value < extraLakeProbability) { cell.WaterLevel = cell.Elevation; cell.Elevation -= 1; } cell = cell.GetNeighbor(direction); } return(length); }
private void TriangulateRoadAdjacentToRiver(HexDirectionEnum direction, HexCell cell, Vector3 center, EdgeVertices edge) { bool hasRoadThroughEdge = cell.HasRoadThroughEdge(direction); bool previousHasRiver = cell.HasRiverThroughEdge(direction.Previous( )); bool nextHasRiver = cell.HasRiverThroughEdge(direction.Next( )); Vector2 interpolators = GetRoadInterpolators(direction, cell); Vector3 roadCenter = center; if (cell.HasRiverBeginOrEnd) { roadCenter += HexMetrics.GetSolidEdgeMiddle(cell.RiverBeginOrEndDirection.Opposite( )) * (1f / 3f); } else if (cell.InComingRive == cell.OutGoingRive.Opposite()) { Vector3 corner; if (previousHasRiver) { if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Next( ))) { return; } corner = HexMetrics.GetSecondSolidCorner(direction); } else { if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Previous())) { return; } corner = HexMetrics.GetFirstSolidCorner(direction); } roadCenter += corner * 0.5f; //桥梁 if (cell.InComingRive == direction.Next() && cell.HasRoadThroughEdge(direction.Next(2)) || cell.HasRoadThroughEdge(direction.Opposite())) { feature.AddBridge(roadCenter, center - corner * 0.5f); } center += corner * 0.25f; } else if (cell.InComingRive == cell.OutGoingRive.Previous( )) { roadCenter -= HexMetrics.GetSecondCorner(cell.InComingRive) * 0.2f; } else if (cell.InComingRive == cell.OutGoingRive.Next( )) { roadCenter -= HexMetrics.GetFirstCorner(cell.InComingRive) * 0.2f; } else if (previousHasRiver && nextHasRiver) { if (!hasRoadThroughEdge) { return; } Vector3 offset = HexMetrics.GetSolidEdgeMiddle(direction) * HexMetrics.innerToOuter; roadCenter += offset * 0.7f; center += offset * 0.5f; } else { HexDirectionEnum middle; if (previousHasRiver) { middle = direction.Next( ); } else if (nextHasRiver) { middle = direction.Previous( ); } else { middle = direction; } if (!cell.HasRoadThroughEdge(middle) && !cell.HasRoadThroughEdge(middle.Previous( )) && !cell.HasRoadThroughEdge(middle.Next( ))) { return; } Vector3 offset = HexMetrics.GetSolidEdgeMiddle(middle); roadCenter += offset * 0.25f; //桥梁 if (direction == middle && cell.HasRoadThroughEdge(direction.Opposite())) { feature.AddBridge(roadCenter, center - offset * (HexMetrics.innerToOuter * 0.7f)); } } Vector3 mL = Vector3.Lerp(roadCenter, edge.v1, interpolators.x); Vector3 mR = Vector3.Lerp(roadCenter, edge.v5, interpolators.y); TriangulateRoad(roadCenter, mL, mR, edge, hasRoadThroughEdge, cell.Index); if (previousHasRiver) { TriangulateRoadEdge(roadCenter, center, mL, cell.Index); } if (nextHasRiver) { TriangulateRoadEdge(roadCenter, mR, center, cell.Index); } }
private void TrangulateConnection(HexDirectionEnum direction, HexCell cell, EdgeVertices edge) { HexCell neighbor = cell.GetNeighbor(direction); if (neighbor == null) { //NoNeighborConnection( direction , cell , edge ) ; return; } Vector3 bridge = HexMetrics.GetTwoBridge(direction); bridge.y = neighbor.Position.y - cell.Position.y; EdgeVertices edge2 = new EdgeVertices(edge.v1 + bridge, edge.v5 + bridge); bool hasRiver = cell.HasRiverThroughEdge(direction); bool hasRoad = cell.HasRoadThroughEdge(direction); if (hasRiver) { edge2.v3.y = neighbor.StreamBedHight; Vector3 indices; indices.x = indices.z = cell.Index; indices.y = neighbor.Index; if (!cell.IsUnderWater) { if (!neighbor.IsUnderWater) { TriangulateRiverQuad(edge.v2, edge.v4, edge2.v2, edge2.v4, cell.RiverSurfaceHight, neighbor.RiverSurfaceHight, 0.8f, cell.HasInComingRiver && cell.InComingRive == direction, indices); } else if (cell.Elevation > neighbor.WaterLevel) { TriangulateWaterFallInWater(edge.v2, edge.v4, edge2.v2, edge2.v4, cell.RiverSurfaceHight, neighbor.RiverSurfaceHight, neighbor.WaterSurfaceHight, indices); } } else if (!neighbor.IsUnderWater && neighbor.Elevation > cell.WaterLevel) { TriangulateWaterFallInWater(edge2.v4, edge2.v2, edge.v4, edge.v2, neighbor.RiverSurfaceHight, cell.RiverSurfaceHight, cell.WaterSurfaceHight, indices); } } if (cell.GetEdgeType(direction) == HexEdgeType.Slope) { TriangulateEdgeTerraces(edge, cell, edge2, neighbor, hasRoad); } else { TriangulateEdgeStrip(edge, weights1, cell.Index, edge2, weights2, neighbor.Index, hasRoad); } feature.AddWall(edge, cell, edge2, neighbor, hasRiver, hasRoad); //处理三角形 HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); if (nextNeighbor != null) { //避免重复绘制,只绘制左上和上方的三角 if (direction != HexDirectionEnum.BottomRight) { Vector3 v5 = edge.v5 + HexMetrics.GetTwoBridge(direction.Next()); v5.y = nextNeighbor.Position.y; if (cell.Elevation <= neighbor.Elevation) { if (cell.Elevation <= nextNeighbor.Elevation) { TriangulateCorner(edge.v5, cell, edge2.v5, neighbor, v5, nextNeighbor); } else { TriangulateCorner(v5, nextNeighbor, edge.v5, cell, edge2.v5, neighbor); } } else if (neighbor.Elevation <= nextNeighbor.Elevation) { TriangulateCorner(edge2.v5, neighbor, v5, nextNeighbor, edge.v5, cell); } else { TriangulateCorner(v5, nextNeighbor, edge.v5, cell, edge2.v5, neighbor); } } } /*else { * * //绘制缺失的小三角 * HexCell noneCell = new GameObject().AddComponent<HexCell>() ; * noneCell.Index = neighbor.Index ; * Vector3 v5 = cell.postion + HexMetrics.GetSecondCorner( direction ) ; * v5.y = 0 ; * TriangulateCorner( edge.v5 , cell , edge2.v5 , neighbor , v5 , noneCell ) ; * DestroyObject( noneCell.gameObject ) ; * } * * //绘制缺失的小三角 * HexCell prevNeighbor = cell.GetNeighbor( direction.Previous() ) ; * if ( prevNeighbor == null ) { * HexCell noneCell = new GameObject().AddComponent<HexCell>() ; * noneCell.Index = neighbor.Index; * Vector3 v5 = cell.postion + HexMetrics.GetFirstCorner( direction ) ; * v5.y = 0 ; * TriangulateCorner( edge.v1 , cell , v5 , noneCell , edge2.v1 , neighbor) ; * DestroyObject( noneCell.gameObject ) ; * }*/ }
private void TriangulateWaterShore(HexDirectionEnum direction, HexCell cell, HexCell neighbor, Vector3 center) { Vector3 c1 = center + HexMetrics.GetWaterFirstCorner(direction); Vector3 c2 = center + HexMetrics.GetWaterSecondCorner(direction); EdgeVertices e1 = new EdgeVertices(c1, c2); water.AddPerturTriangle(center, e1.v1, e1.v2); water.AddPerturTriangle(center, e1.v2, e1.v3); water.AddPerturTriangle(center, e1.v3, e1.v4); water.AddPerturTriangle(center, e1.v4, e1.v5); Vector3 indices; indices.x = indices.z = cell.Index; indices.y = neighbor.Index; water.AddTriangleCellData(indices, weights1); water.AddTriangleCellData(indices, weights1); water.AddTriangleCellData(indices, weights1); water.AddTriangleCellData(indices, weights1); Vector3 center2 = neighbor.Position; if (neighbor.ColumnIndex < cell.ColumnIndex - 1) { center2.x += HexMetrics.wrapSize * HexMetrics.innerDiameter; } else if (neighbor.ColumnIndex > cell.ColumnIndex + 1) { center2.x -= HexMetrics.wrapSize * HexMetrics.innerDiameter; } center2.y = center.y; EdgeVertices e2 = new EdgeVertices(center2 + HexMetrics.GetSecondSolidCorner(direction.Opposite()), center2 + HexMetrics.GetFirstSolidCorner(direction.Opposite())); if (cell.HasRiverThroughEdge(direction)) { TriangulateEstuary(e1, e2, cell.HasInComingRiver && cell.InComingRive == direction, indices); } else { waterShore.AddPerturQuad(e1.v1, e1.v2, e2.v1, e2.v2); waterShore.AddPerturQuad(e1.v2, e1.v3, e2.v2, e2.v3); waterShore.AddPerturQuad(e1.v3, e1.v4, e2.v3, e2.v4); waterShore.AddPerturQuad(e1.v4, e1.v5, e2.v4, e2.v5); waterShore.AddQuadUV(0f, 0f, 0f, 1f); waterShore.AddQuadUV(0f, 0f, 0f, 1f); waterShore.AddQuadUV(0f, 0f, 0f, 1f); waterShore.AddQuadUV(0f, 0f, 0f, 1f); waterShore.AddQuadCellData(indices, weights1, weights2); waterShore.AddQuadCellData(indices, weights1, weights2); waterShore.AddQuadCellData(indices, weights1, weights2); waterShore.AddQuadCellData(indices, weights1, weights2); } HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); if (nextNeighbor != null) { Vector3 center3 = nextNeighbor.Position; if (nextNeighbor.ColumnIndex < cell.ColumnIndex - 1) { center3.x += HexMetrics.wrapSize * HexMetrics.innerDiameter; } else if (nextNeighbor.ColumnIndex > cell.ColumnIndex + 1) { center3.x -= HexMetrics.wrapSize * HexMetrics.innerDiameter; } Vector3 v3 = center3 + (nextNeighbor.IsUnderWater ? HexMetrics.GetWaterFirstCorner(direction.Previous()) : HexMetrics.GetFirstSolidCorner(direction.Previous())); v3.y = center.y; waterShore.AddPerturTriangle(e1.v5, e2.v5, v3); waterShore.AddTriangleUV(Vector2.zero, Vector2.up, nextNeighbor.IsUnderWater ? Vector2.zero : Vector2.up); indices.z = nextNeighbor.Index; waterShore.AddTriangleCellData(indices, weights1, weights2, weights3); } }
//下一个三角 public static HexDirectionEnum Next(this HexDirectionEnum direction) { /*direction += 1 ; * if ( direction >= HexDirectionEnum.Length ) direction -= (int) HexDirectionEnum.Length ;*/ return(direction.Next(1)); }