/// <summary> /// 三角化沿岸水体单元 /// </summary> /// <param name="direction"></param> /// <param name="cell"></param> /// <param name="neighbor"></param> /// <param name="center"></param> void TriangulateWaterShore(HexDirection direction, HexCell cell, HexCell neighbor, Vector3 center) { EdgeVertices e1 = new EdgeVertices( center + HexMetrics.GetFirstWaterCorner(direction), center + HexMetrics.GetSecondWaterCorner(direction) ); water.AddTriangle(center, e1.v1, e1.v2); water.AddTriangle(center, e1.v2, e1.v3); water.AddTriangle(center, e1.v3, e1.v4); water.AddTriangle(center, e1.v4, e1.v5); Vector3 indices; //indices.x = indices.y = indices.z = cell.Index; 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 bridge = HexMetrics.GetWaterBridge(direction); 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.IncomingRiver == direction, indices); } else { waterShore.AddQuad(e1.v1, e1.v2, e2.v1, e2.v2); waterShore.AddQuad(e1.v2, e1.v3, e2.v2, e2.v3); waterShore.AddQuad(e1.v3, e1.v4, e2.v3, e2.v4); waterShore.AddQuad(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; //center3.y = center.y; 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.GetFirstWaterCorner(direction.Previous()) : HexMetrics.GetFirstSolidCorner(direction.Previous()) ); v3.y = center.y; waterShore.AddTriangle(e1.v5, e2.v5, v3); waterShore.AddTriangulateUV(new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, nextNeighbor.IsUnderwater ? 0f : 1f)); indices.z = nextNeighbor.Index; waterShore.AddTriangleCellData(indices, weights1, weights2, weights3); } }
/// <summary> /// 三角化穿过的河道 /// </summary> /// <param name="direction"></param> /// <param name="cell"></param> /// <param name="center"></param> /// <param name="e"></param> void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { Vector3 centerL, centerR; if (cell.HasRiverThroughEdge(direction.Opposite())) { centerL = center + HexMetrics.GetFirstSolidCorner(direction.Previous()) * 0.25f; centerR = center + HexMetrics.GetSecondSolidCorner(direction.Next()) * 0.25f; } else if (cell.HasRiverThroughEdge(direction.Next())) { centerL = center; centerR = Vector3.Lerp(center, e.v5, 2f / 3f); } else if (cell.HasRiverThroughEdge(direction.Previous())) { centerL = Vector3.Lerp(center, e.v1, 2f / 3f); centerR = center; } else if (cell.HasRiverThroughEdge(direction.Next2())) { 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, e.v1, 0.5f), Vector3.Lerp(centerR, e.v5, 0.5f), 1f / 6f); m.v3.y = center.y = e.v3.y; //TriangulateEdgeStrip(m, cell.Color, e, cell.Color); TriangulateEdgeStrip(m, weights1, cell.Index, e, weights1, cell.Index); terrain.AddTriangle(centerL, m.v1, m.v2); //terrain.AddTriangleColor(cell.Color); terrain.AddQuad(centerL, center, m.v2, m.v3); //terrain.AddQuadColor(cell.Color); terrain.AddQuad(center, centerR, m.v3, m.v4); //terrain.AddQuadColor(cell.Color); terrain.AddTriangle(centerR, m.v4, m.v5); //terrain.AddTriangleColor(cell.Color); //terrain.AddTriangleColor(color1); //terrain.AddQuadColor(color1); //terrain.AddQuadColor(color1); //terrain.AddTriangleColor(color1); //Vector3 types; //types.x = types.y = types.z = cell.TerrainTypeIndex; //terrain.AddTriangulateTerrainType(types); //terrain.AddQuadTerrainType(types); //terrain.AddQuadTerrainType(types); //terrain.AddTriangulateTerrainType(types); 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); if (!cell.IsUnderwater) { bool reversed = cell.IncomingRiver == direction; TriangulateRiverQuad(centerL, centerR, m.v2, m.v4, cell.RiverSurfaceY, 0.4f, reversed, indices); TriangulateRiverQuad(m.v2, m.v4, e.v2, e.v4, cell.RiverSurfaceY, 0.6f, reversed, indices); } }
private void AddParticles(Vector3 center, HexDirection direction, HexCell cell) { var x = center.x; var y = center.y; var z = center.z; var curA = new Vector3(0, 0, 0); var curB = new Vector3(0, 0, 0); var step = new Vector3(0, 0, 0); var rows = HexMetrics.OUTER_RADIUS; var v1 = HexMetrics.GetFirstSolidCorner(direction); var v2 = HexMetrics.GetSecondSolidCorner(direction); for (var i = 0; i < HexMetrics.OUTER_RADIUS; i++) { //Draw outer trinagles switch (i) { case 0: curA = new Vector3(x, y, z); break; case 1: curA = new Vector3(x, y, z) + v1 * HexMetrics.PARTICLE_SIZE; break; default: curA = step + v1 * HexMetrics.PARTICLE_SIZE; break; } for (var o = 0; o < rows; o++) { var a = curA; var b = curA + v1 * HexMetrics.PARTICLE_SIZE; var c = curA + v2 * HexMetrics.PARTICLE_SIZE; AdjustHeight(a, b, c, ref cell); curA = curA + v2 * HexMetrics.PARTICLE_SIZE; } //Draw covers switch (i) { case 0: step = new Vector3(x, y, z); curA = step + v2 * HexMetrics.PARTICLE_SIZE; curB = step + v1 * HexMetrics.PARTICLE_SIZE; break; default: step = step + v1 * HexMetrics.PARTICLE_SIZE; curA = step + v2 * HexMetrics.PARTICLE_SIZE; curB = step + v1 * HexMetrics.PARTICLE_SIZE; break; } for (var j = 0; j < rows - 1; j++) { var a = curA; var b = curB; var c = curA + v1 * HexMetrics.PARTICLE_SIZE; AdjustHeight(a, b, c, ref cell); curA = curA + v2 * HexMetrics.PARTICLE_SIZE; curB = curB + v2 * HexMetrics.PARTICLE_SIZE; } rows--; } }
public void TriangulateWaterShore(HexDirection dir, HexCell hexCell, HexCell neighbour, Vector3 center) { EdgeVertices edges1 = new EdgeVertices(center + HexMetrics.GetFirstWaterCorner(dir), center + HexMetrics.GetSecondWaterCorner(dir)); Water.AddTriangle(center, edges1.v1, edges1.v2); Water.AddTriangle(center, edges1.v2, edges1.v3); Water.AddTriangle(center, edges1.v3, edges1.v4); Water.AddTriangle(center, edges1.v4, edges1.v5); Vector3 indices = new Vector3(hexCell.CellIndex, hexCell.CellIndex, hexCell.CellIndex); Water.AddTriangleCellData(indices, Weights1); Water.AddTriangleCellData(indices, Weights1); Water.AddTriangleCellData(indices, Weights1); Water.AddTriangleCellData(indices, Weights1); Vector3 center2 = neighbour.Position; center2.y = center.y; if (neighbour.ColumnIndex < hexCell.ColumnIndex - 1) { center2.x += HexMetrics.WrapSize * HexMetrics.InnerDiameter; } else if (neighbour.ColumnIndex > hexCell.ColumnIndex + 1) { center2.x -= HexMetrics.WrapSize * HexMetrics.InnerDiameter; } Vector3 bridge = HexMetrics.GetWaterBridge(dir); EdgeVertices edges2 = new EdgeVertices(center2 + HexMetrics.GetSecondSolidCorner(dir.Opposite()), center2 + HexMetrics.GetFirstSolidCorner(dir.Opposite())); if (hexCell.HasRiverThroughEdge(dir)) { TriangulateEstuary(edges1, edges2, hexCell.IncomingRiverDirection == dir, indices); } else { WaterShore.AddQuad(edges1.v1, edges1.v2, edges2.v1, edges2.v2); WaterShore.AddQuad(edges1.v2, edges1.v3, edges2.v2, edges2.v3); WaterShore.AddQuad(edges1.v3, edges1.v4, edges2.v3, edges2.v4); WaterShore.AddQuad(edges1.v4, edges1.v5, edges2.v4, edges2.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 nextNeighbour = hexCell.GetNeighbour(dir.Next()); if (nextNeighbour != null) { Vector3 center3 = nextNeighbour.Position; if (nextNeighbour.ColumnIndex < hexCell.ColumnIndex - 1) { center3.x += HexMetrics.WrapSize * HexMetrics.InnerDiameter; } else if (nextNeighbour.ColumnIndex > hexCell.ColumnIndex + 1) { center3.x -= HexMetrics.WrapSize * HexMetrics.InnerDiameter; } Vector3 v3 = center3 + (nextNeighbour.IsUnderwater ? HexMetrics.GetFirstWaterCorner(dir.Previous()) : HexMetrics.GetFirstSolidCorner(dir.Previous())); v3.y = center.y; WaterShore.AddTriangle(edges1.v5, edges2.v5, v3); WaterShore.AddTriangleUV(new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, 0f)); WaterShore.AddTriangleCellData(indices, Weights1, Weights2, Weights3); } } }
/// <summary> /// 三角化有河流的六边形内的道路 /// </summary> /// <param name="direction"></param> /// <param name="cell"></param> /// <param name="center">六边形的中心</param> /// <param name="e"></param> void TriangulateRoadAdjacentToRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { 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.IncomingRiver == cell.OutgoingRiver.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.IncomingRiver == direction.Next() && // 由于有多个没有河流经过的扇形,所以只选取一个方向的扇形添加桥梁,保证只实例化一次桥梁 (cell.HasRoadThroughEdge(direction.Next2()) || cell.HasRoadThroughEdge(direction.Opposite()))) // 河流对面的扇形也有道路才添加桥梁 { features.AddBridge(roadCenter, center - corner * 0.5f); // 沿着河流垂线找到桥的第二个端点 } // 六边形中心也往外推 center += corner * 0.25f; } // 如果流入河流与流出河流相邻 else if (cell.IncomingRiver == cell.OutgoingRiver.Previous()) { // 道路中心往流入流出河流的相交尖端方向推 roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiver) * 0.2f; } // 如果流入河流与流出河流相邻 else if (cell.IncomingRiver == cell.OutgoingRiver.Next()) { // 道路中心往流入流出河流的相交尖端方向推 roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiver) * 0.2f; } // 如果扇形上一个方向有河流,下一个方向也有河流(流出流入河流相隔一个扇形,当前扇形位于河流弧度的内侧) else if (previousHasRiver && nextHasRiver) { // 如果扇形里没有道路,则返回不进行道路三角化 if (!hasRoadThroughEdge) { return; } Vector3 offset = HexMetrics.GetSolidEdgeMiddle(direction) * HexMetrics.innerToOuter; roadCenter += offset * 0.7f; center += offset * 0.5f; // 该参数与三角化河流那里一样用0.5,可以刚好移到河流边缘(TriangulateAdjacentToRiver方法内) } // 流出流入河流相隔一个扇形,且当前扇形位于河流弧度的外侧 else { HexDirection 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())) // 河对岸也要有道路 { features.AddBridge(roadCenter, center - offset * (HexMetrics.innerToOuter * 0.7f)); // 这里的第二个参数为道路在河流弧度内侧时的道路中心 } } // 三角化道路 Vector3 mL = Vector3.Lerp(roadCenter, e.v1, interpolators.x); Vector3 mR = Vector3.Lerp(roadCenter, e.v5, interpolators.y); TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge, cell.Index); // 如果上一个方向有河流,则三角化一个道路边缘填补空隙 if (previousHasRiver) { TriangulateRoadEdge(roadCenter, center, mL, cell.Index); } // 如果下一个方向有河流,则三角化一个道路边缘填补空隙 if (nextHasRiver) { TriangulateRoadEdge(roadCenter, mR, center, cell.Index); } }
private void triangulateWaterShore( HexDirection direction, HexCell cell, HexCell neighbor, Vector3 center) { EdgeVertices e1 = new EdgeVertices( center + HexMetrics.GetFirstWaterCorner(direction), center + HexMetrics.GetSecondWaterCorner(direction)); water.AddTriangle(center, e1.v1, e1.v2); water.AddTriangle(center, e1.v2, e1.v3); water.AddTriangle(center, e1.v3, e1.v4); water.AddTriangle(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; 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.IncomingRiver == direction, indices); } else { waterShore.AddQuad(e1.v1, e1.v2, e2.v1, e2.v2); waterShore.AddQuad(e1.v2, e1.v3, e2.v2, e2.v3); waterShore.AddQuad(e1.v3, e1.v4, e2.v3, e2.v4); waterShore.AddQuad(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 v3 = nextNeighbor.Position + (nextNeighbor.IsUnderwater ? HexMetrics.GetFirstWaterCorner(direction.Previous()) : HexMetrics.GetFirstSolidCorner(direction.Previous())); v3.y = center.y; waterShore.AddTriangle(e1.v5, e2.v5, v3); waterShore.AddTriangleUV( new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, nextNeighbor.IsUnderwater ? 0f : 1f)); indices.z = nextNeighbor.Index; waterShore.AddTriangleCellData( indices, weights1, weights2, weights3); } }
/// <summary> /// 三角化沿岸水面扇形 /// </summary> /// <param name="direction">当前处理的扇形方向</param> /// <param name="cell">自身六边形</param> /// <param name="neighbor">邻居六边形</param> /// <param name="center">自身六边形中点</param> void TriangulateWaterShore(HexDirection direction, HexCell cell, HexCell neighbor, Vector3 center) { center.y = cell.WaterSurfaceY; Vector3 c1 = center + HexMetrics.GetFirstWaterCorner(direction); Vector3 c2 = center + HexMetrics.GetSecondWaterCorner(direction); EdgeVertices e1 = new EdgeVertices(c1, c2); // 三角化沿岸扇形 water.AddTriangle(center, e1.v1, e1.v2); water.AddTriangle(center, e1.v2, e1.v3); water.AddTriangle(center, e1.v3, e1.v4); water.AddTriangle(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 neighbor_center = neighbor.Position; neighbor_center.y = center.y; // 保持y与自身等高 // 得到邻居纯色区的弧(边) EdgeVertices e2 = new EdgeVertices(neighbor_center + HexMetrics.GetSecondSolidCorner(direction.Opposite()), neighbor_center + HexMetrics.GetFirstSolidCorner(direction.Opposite())); if (cell.HasRiverThroughEdge(direction)) { TriangulateEstuary(e1, e2, cell.HasIncomingRiver && cell.IncomingRiver == direction, indices); } else { waterShore.AddQuad(e1.v1, e1.v2, e2.v1, e2.v2); waterShore.AddQuad(e1.v2, e1.v3, e2.v2, e2.v3); waterShore.AddQuad(e1.v3, e1.v4, e2.v3, e2.v4); waterShore.AddQuad(e1.v4, e1.v5, e2.v4, e2.v5); waterShore.AddQuadUV(0, 0, 0, 1); // 陆地一侧v坐标为1 waterShore.AddQuadUV(0, 0, 0, 1); waterShore.AddQuadUV(0, 0, 0, 1); waterShore.AddQuadUV(0, 0, 0, 1); 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 v3 = nextNeighbor.Position + (nextNeighbor.IsUnderwater ? HexMetrics.GetFirstWaterCorner(direction.Previous()) : HexMetrics.GetFirstSolidCorner(direction.Previous())); // 判断是水面还是陆地,二者纯色区域占比不一样 v3.y = center.y; // 保持y与自身等高 waterShore.AddTriangle(e1.v5, e2.v5, v3); waterShore.AddTriangleUV(new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, nextNeighbor.IsUnderwater ? 0f : 1f)); // 第三个顶点需要判断是在水面还是陆地,水面v为0,陆地用v为1 indices.z = nextNeighbor.Index; waterShore.AddTriangleCellData(indices, weights1, weights2, weights3); } }
private void TriangulateRoadAdjacentToRiver( HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e ) { 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; // Push the road center in the opposite direction of the river. This is // so that the road does not overlap with the river's begin or end. if (cell.HasRiverBeginOrEnd) { // Displace the center 1/3 of the distance to the edge middle point of the opposite direction. roadCenter += HexMetrics.GetSolidEdgeMiddle(cell.RiverBeginOrEndDirection.Opposite()) * (1f / 3f); // River crosses through the cell. } else if (cell.IncomingRiver == cell.OutgoingRiver.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; center += corner * 0.25f; // Zig Zag cases // Move the road center by using one of the corners of the incoming river direction. // Push the road center away from that corner. } else if (cell.IncomingRiver == cell.OutgoingRiver.Previous()) { roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiver) * 0.2f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Next()) { roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiver) * 0.2f; // Inside of Curved Rivers // River on both sides of the current direction, that means there is a curved river. In // this case pull the Road towards the current cell edge, shortening the road. } else if (previousHasRiver && nextHasRiver) { // Prune isolated road parts, that is, do not render a road through that edge. if (!hasRoadThroughEdge) { return; } Vector3 offset = HexMetrics.GetSolidEdgeMiddle(direction) * HexMetrics.innerToOuter; roadCenter += offset * 0.7f; center += offset * 0.5f; // Outside of a curving river // There are three cell parts on the outside, we have to // find the middle direction. } else { HexDirection middle; if (previousHasRiver) { middle = direction.Next(); } else if (nextHasRiver) { middle = direction.Previous(); } else { middle = direction; } // Prune this side of the river if there is no road that continues through // this direction, the previous or the next one. if (!cell.HasRoadThroughEdge(middle) && !cell.HasRoadThroughEdge(middle.Previous()) && !cell.HasRoadThroughEdge(middle.Next())) { return; } roadCenter += HexMetrics.GetSolidEdgeMiddle(middle) * 0.25f; } Vector3 mL = Vector3.Lerp(roadCenter, e.v1, interpolators.x); Vector3 mR = Vector3.Lerp(roadCenter, e.v5, interpolators.y); TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge); if (previousHasRiver) { TriangulateRoadEdge(roadCenter, center, mL); } if (nextHasRiver) { TriangulateRoadEdge(roadCenter, mR, center); } }
/// <summary> /// 生成有河流的三角网格 /// </summary> /// <param name="direction">处理的对应方向</param> /// <param name="cell">六边形对象引用</param> /// <param name="center">中心点坐标</param> /// <param name="e">边界中值插值对象</param> void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { Vector3 centerL, centerR; if (cell.HasRiverThroughEdge(direction.Opposite())) { // 河道拓宽为直线的左边界点,后续逻辑以此类推 // 总之向转弯内侧进行网格拼接 centerL = center + HexMetrics.GetFirstSolidCorner(direction.Previous()) * 0.25f; centerR = center + HexMetrics.GetSecondSolidCorner(direction.Next()) * 0.25f; } else if (cell.HasRiverThroughEdge(direction.Next())) { centerL = center; centerR = Vector3.Lerp(center, e.v5, 2f / 3f); } else if (cell.HasRiverThroughEdge(direction.Previous())) { centerL = Vector3.Lerp(center, e.v1, 2f / 3f); centerR = center; } else if (cell.HasRiverThroughEdge(direction.Next2())) { 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, e.v1, 0.5f), Vector3.Lerp(centerR, e.v5, 0.5f), 1f / 6f ); // 同步河道底部高度 m.v3.y = center.y = e.v3.y; // 填充插值中间点与边界间的平面 TriangulateEdgeStrip(m, cell.Color, e, cell.Color); // 根据计算进行网格拼接 terrain.AddTriangle(centerL, m.v1, m.v2); terrain.AddTriangleColor(cell.Color); terrain.AddQuad(centerL, center, m.v2, m.v3); terrain.AddQuadColor(cell.Color); terrain.AddQuad(center, centerR, m.v3, m.v4); terrain.AddQuadColor(cell.Color); terrain.AddTriangle(centerR, m.v4, m.v5); terrain.AddTriangleColor(cell.Color); // 排除河流在水面下显示 if (!cell.IsUnderwater) { bool reversed = cell.IncomingRiver == direction; TriangulateRiverQuad( centerL, centerR, m.v2, m.v4, cell.RiverSurfaceY, 0.4f, reversed ); TriangulateRiverQuad( m.v2, m.v4, e.v2, e.v4, cell.RiverSurfaceY, 0.6f, reversed ); } }
/// <summary> /// 道路临近河流时的网格处理 /// </summary> /// <param name="direction"></param> /// <param name="cell"></param> /// <param name="center"></param> /// <param name="e"></param> void TriangulateRoadAdjacentToRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { 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.IncomingRiver == cell.OutgoingRiver.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; center += corner * 0.25f; } // 对于Z字形河流的道路填充判断 else if (cell.IncomingRiver == cell.OutgoingRiver.Previous()) { // 使道路中心远离河流流入方向向量的0.2 roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiver) * 0.2f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Next()) { // 使道路中心远离河流流入方向向量的0.2 roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiver) * 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 { // 确定转弯弧外侧的中间方向 HexDirection 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; } // 将道路弧向中间方向的边界移动25% roadCenter += HexMetrics.GetSolidEdgeMiddle(middle) * 0.25f; } Vector3 mL = Vector3.Lerp(roadCenter, e.v1, interpolators.x); Vector3 mR = Vector3.Lerp(roadCenter, e.v5, interpolators.y); TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge); // 平滑处理道路与河流相遇的网格,闭合网格空隙 if (previousHasRiver) { TriangulateRoadEdge(roadCenter, center, mL); } if (nextHasRiver) { TriangulateRoadEdge(roadCenter, mR, center); } }
void BoundaryEdge(HexDirection d, HexCell cell) { HexCell neighbor = cell.GetNeighbor(d); if (neighbor != null) { return; } //Only check boundaries HexCell neighbor2 = cell.GetNeighbor(d.Next()); HexCell neighbor3 = cell.GetNeighbor(d.Previous()); Vector3 center = cell.transform.localPosition; Vector3 center2, v1, v2, v3, v4, tempV1; //Generate basic hex edge on any boundary v1 = center + HexMetrics.GetSecondSolidCorner(d, cell); v2 = center + HexMetrics.GetFirstSolidCorner(d, cell); tempV1 = ((cell.Height) * Vector3.up * HexMetrics.heightStep); v3 = (v1 - tempV1); v4 = (v2 - tempV1); AddTriangle(center + (((HexMetrics.GetFirstSolidCorner(d, cell)) + HexMetrics.GetSecondSolidCorner(d.Opposite(), cell)) / 2), (v2), (v1)); AddTriangleColor(cell.color); AddQuad(v2, v1, v4, v3); AddQuadColor(cell.color, cell.color); if (neighbor2 == null) { } else if (!neighbor2.Checked[(int)d]) //Check right neighbor, add boundary edge if there isn't one { center2 = neighbor2.transform.position; v1 = center + HexMetrics.GetSecondSolidCorner(d, cell); v2 = center2 + HexMetrics.GetFirstSolidCorner(d.Previous(), neighbor2); tempV1 = cell.Height * Vector3.up * HexMetrics.heightStep; v3 = v1 - tempV1; tempV1 = neighbor2.Height * Vector3.up * HexMetrics.heightStep; v4 = v2 - tempV1; AddQuad(v1, v2, v3, v4); AddQuadColor(neighbor2.color, cell.color); neighbor2.Checked[(int)d] = true; } if (neighbor3 == null) { } else if (!neighbor3.Checked[(int)d]) //Check left neighbor, add boundary edge if there isn't one { center2 = neighbor3.transform.position; v1 = center2 + HexMetrics.GetSecondSolidCorner(d.Next(), neighbor3); v2 = center + HexMetrics.GetFirstSolidCorner(d, cell); tempV1 = neighbor3.Height * Vector3.up * HexMetrics.heightStep; v3 = v1 - tempV1; tempV1 = cell.Height * Vector3.up * HexMetrics.heightStep; v4 = v2 - tempV1; AddQuad(v1, v2, v3, v4); AddQuadColor(neighbor3.color, cell.color); neighbor3.Checked[(int)d] = true; } }
void TriangulateRoadAdjacentToRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { 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; // Push road center away from river if (cell.HasRiverBeginOrEnd) { roadCenter += HexMetrics.GetSolidEdgeMiddle(cell.RiverBeginOrEndDirection.Opposite()) * (1f / 3f); } // Disconnect road on opposite side of river else if (cell.IncomingRiver == cell.OutgoingRiver.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; center += corner * 0.25f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Previous()) { roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiver) * 0.2f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Next()) { roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiver) * 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 { HexDirection 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; } roadCenter += HexMetrics.GetSolidEdgeMiddle(middle) * 0.25f; } Vector3 mL = Vector3.Lerp(roadCenter, e.v1, interpolators.x); Vector3 mR = Vector3.Lerp(roadCenter, e.v5, interpolators.y); TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge); // Close gaps in road created by river if (previousHasRiver) { TriangulateRoadEdge(roadCenter, center, mL); } if (nextHasRiver) { TriangulateRoadEdge(roadCenter, mR, center); } }
/// <summary> /// 河流穿过cell /// </summary> /// <param name="direction"></param> /// <param name="cell"></param> /// <param name="center"></param> /// <param name="e"></param> void TriangulateWithRiver( HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e ) { Vector3 centerL, centerR; // 河流对穿cell if (cell.HasRiverThroughEdge(direction.Opposite())) { // 画出中间沟槽 centerL = center + HexMetrics.GetFirstSolidCorner(direction.Previous()) * 0.25f; centerR = center + HexMetrics.GetSecondSolidCorner(direction.Next()) * 0.25f; } // 河流一步回转,下位穿出 else if (cell.HasRiverThroughEdge(direction.Next())) { centerL = center; centerR = Vector3.Lerp(center, e.v5, 2f / 3f); } // 河流一步回转,上位穿出 else if (cell.HasRiverThroughEdge(direction.Previous())) { centerL = Vector3.Lerp(center, e.v1, 2f / 3f); centerR = center; } // 河流二步回转,下位穿出 else if (cell.HasRiverThroughEdge(direction.Next2())) { 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, e.v1, 0.5f), Vector3.Lerp(centerR, e.v5, 0.5f), 1f / 6f ); m.v3.y = center.y = e.v3.y; TriangulateEdgeStrip(m, cell.Color, e, cell.Color); terrain.AddTriangle(centerL, m.v1, m.v2); terrain.AddTriangleColor(cell.Color); terrain.AddQuad(centerL, center, m.v2, m.v3); terrain.AddQuadColor(cell.Color); terrain.AddQuad(center, centerR, m.v3, m.v4); terrain.AddQuadColor(cell.Color); terrain.AddTriangle(centerR, m.v4, m.v5); terrain.AddTriangleColor(cell.Color); bool reversed = cell.IncomingRiver == direction; TriangulateRiverQuad( centerL, centerR, m.v2, m.v4, cell.RiverSurfaceY, 0.4f, reversed ); TriangulateRiverQuad( m.v2, m.v4, e.v2, e.v4, cell.RiverSurfaceY, 0.6f, reversed ); }
/// <summary> /// 三角化道路,临近河流时 /// </summary> /// <param name="direction"></param> /// <param name="cell"></param> /// <param name="center"></param> /// <param name="e"></param> void TriangulateRoadAdjacentToRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { 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.IncomingRiver == cell.OutgoingRiver.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.IncomingRiver == direction.Next() && (cell.HasRoadThroughEdge(direction.Next2()) || cell.HasRoadThroughEdge(direction.Opposite())) ) { features.AddBridge(roadCenter, center - center * 0.5f); } center += corner * 0.25f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Previous()) { roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiver) * 0.2f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Next()) { roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiver) * 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 { HexDirection 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 += HexMetrics.GetSolidEdgeMiddle(middle) * 0.25f; roadCenter += offset * 0.25f; //弯曲河流加入桥梁 if ( direction == middle && cell.HasRoadThroughEdge(direction.Opposite()) ) { features.AddBridge(roadCenter, center - offset * (HexMetrics.innerToOuter * 0.7f)); } } Vector3 mL = Vector3.Lerp(roadCenter, e.v1, interpolators.x); Vector3 mR = Vector3.Lerp(roadCenter, e.v5, interpolators.y); TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge, cell.Index); if (previousHasRiver) { TriangulateRoadEdge(roadCenter, center, mL, cell.Index); } if (nextHasRiver) { TriangulateRoadEdge(roadCenter, mR, center, cell.Index); } }
/// <summary> /// 三角化有河流流过(有流出也有流入)的六边形内部的有河流的扇形 /// </summary> /// <param name="direction"></param> /// <param name="cell"></param> /// <param name="center"></param> /// <param name="e"></param> void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { Vector3 centerL; //六边形中心线的左边顶点 Vector3 centerR; //六边形中心线的左边顶点 // 如果流入和流出方向刚好相反(河道是一条直线) if (cell.HasRiverThroughEdge(direction.Opposite())) { // 把六边形中心点扩展成一条垂直于河道的线(中心线) centerL = center + HexMetrics.GetFirstSolidCorner(direction.Previous()) * 0.25f; // 计算出中心线的左边顶点 centerR = center + HexMetrics.GetSecondSolidCorner(direction.Next()) * 0.25f; // 计算出中心线的右边顶点 } // 如果流入方向和流出方向相邻 else if (cell.HasRiverThroughEdge(direction.Next())) { centerL = center; centerR = Vector3.Lerp(center, e.v5, 2 / 3f); // 把中心线右顶点往外部移动,让中心河道宽一点 } // 如果流入方向和流出方向相邻 else if (cell.HasRiverThroughEdge(direction.Previous())) { centerL = Vector3.Lerp(center, e.v1, 2 / 3f); // 把中心线左顶点往外部移动,让中心河道宽一点 centerR = center; } // 如果流入方向和流出方向相隔一个扇形 else if (cell.HasRiverThroughEdge(direction.Next2())) { centerL = center; centerR = center + HexMetrics.GetSolidEdgeMiddle(direction.Next()) * (0.5f * HexMetrics.innerToOuter); // 调整中心线右顶点,使河道变宽 } // 如果流入方向和流出方向相隔一个扇形 else { centerL = center + HexMetrics.GetSolidEdgeMiddle(direction.Previous()) * (0.5f * HexMetrics.innerToOuter);// 调整中心线右顶点,使河道变宽 centerR = centerR = center; } // 计算出中心线与外部边缘的中线 // 梯形: // 外部边缘: ———— // 中线: -——- // 六边形中心线: —— EdgeVertices m = new EdgeVertices(Vector3.Lerp(centerL, e.v1, 0.5f), Vector3.Lerp(centerR, e.v5, 0.5f), 1 / 6f); center = Vector3.Lerp(centerL, centerR, 0.5f); // 中心点重新设置为中心线两顶点的中点 m.v3.y = center.y = e.v3.y; // 调整中线的中心顶点的高度为河床高度 // 三角化中线到外部边缘之间的长方形 TriangulateEdgeStrip(m, weights1, cell.Index, e, weights1, cell.Index); // 三角化六边形中心线到梯形中线的梯形(两个三角形,两个长方形) terrain.AddTriangle(centerL, m.v1, m.v2); terrain.AddQuad(centerL, center, m.v2, m.v3); terrain.AddQuad(center, centerR, m.v3, m.v4); terrain.AddTriangle(centerR, m.v4, m.v5); // 顶点附近三个六边形格子的索引和splat贴图颜色 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); // 三角化河水 if (!cell.IsUnderwater) // 检查是否在陆地,如果在陆地则三角化河水 { bool reversed = cell.IncomingRiver == direction; // 流入河水需要翻转UV TriangulateRiverQuad(centerL, centerR, m.v2, m.v4, cell.RiverSurfaceY, 0.4f, reversed, indices); TriangulateRiverQuad(m.v2, m.v4, e.v2, e.v4, cell.RiverSurfaceY, 0.6f, reversed, indices); } }
public void SmoothEdges() { List <HexGridChunk> chunks = new List <HexGridChunk>(); HexGridChunk chunk; for (int z = 1; z < cellCountZ - 2; z++) { for (int x = 2; x < cellCountX - 2; x++) { chunk = cells[x, z].chunk; HexCell currentCell = cells[x, z]; Vector3 center = currentCell.transform.localPosition; Vector3 center2; Vector3 v1, v2, v3, v4; HexCell Neighbor, nextNeighbor, otherNeighbor; HexCell NeighborNeighbor; for (HexDirection d = HexDirection.NE; d < HexDirection.NW; d++) { Neighbor = currentCell.GetNeighbor(d); NeighborNeighbor = Neighbor.GetNeighbor(d.Next()); nextNeighbor = currentCell.GetNeighbor(d.Next()); otherNeighbor = currentCell.GetNeighbor(d.Next().Next()); if (Neighbor != null && (nextNeighbor != null)) { if ((currentCell.Height == Neighbor.Height) && (currentCell.Height > nextNeighbor.Height) && ((currentCell.Height - nextNeighbor.Height) < heightSmoothRange)) { center2 = Neighbor.transform.localPosition; v1 = v3 = center + HexMetrics.GetSecondSolidCorner(d.Next(), currentCell); v2 = v4 = center2 + HexMetrics.GetFirstSolidCorner(d.Previous().Opposite(), Neighbor); v3.y = v4.y = (nextNeighbor.Height) * HexMetrics.heightStep; if (otherNeighbor != null) { if ((nextNeighbor.Height) > otherNeighbor.Height) { v4 = (nextNeighbor.transform.localPosition - HexMetrics.GetFirstSolidCorner(d.Opposite(), nextNeighbor)); } if (NeighborNeighbor != null) { if (nextNeighbor.Height > Neighbor.GetNeighbor(d.Next()).Height) { v3 = (nextNeighbor.transform.localPosition - HexMetrics.GetSecondSolidCorner(d, nextNeighbor)); } } if (NeighborNeighbor != null) { if (!(nextNeighbor.Height > otherNeighbor.Height || nextNeighbor.Height > NeighborNeighbor.Height)) { v3 += (HexMetrics.GetSecondSolidCorner(d.Next(), currentCell) / 100) * 65; v4 += (HexMetrics.GetSecondSolidCorner(d.Next(), currentCell) / 100) * 65; } } else { if (!(nextNeighbor.Height > otherNeighbor.Height)) { v3 += (HexMetrics.GetSecondSolidCorner(d.Next(), currentCell) / 100) * 65; v4 += (HexMetrics.GetSecondSolidCorner(d.Next(), currentCell) / 100) * 65; } } } if (otherNeighbor != null && NeighborNeighbor != null) { v4 = (nextNeighbor.transform.localPosition - HexMetrics.GetFirstSolidCorner(d.Opposite(), nextNeighbor)); v3 = (nextNeighbor.transform.localPosition - HexMetrics.GetSecondSolidCorner(d, nextNeighbor)); } //chunk.hexMesh.AddTriangle(center + ((HexMetrics.GetFirstSolidCorner(d, currentCell) + HexMetrics.GetSecondSolidCorner(d.Opposite(), currentCell)) / 2), (v2), (v1)); //chunk.hexMesh.AddTriangleColor(currentCell.color); chunk.hexMesh.AddQuad(center2, center, v2, v1); chunk.hexMesh.AddQuadColor(currentCell.color, Neighbor.color); chunk.hexMesh.AddQuad(v2, v1, v4, v3); chunk.hexMesh.AddQuadColor(currentCell.color, nextNeighbor.color); chunks.Add(chunk); } } } } } foreach (HexGridChunk c in chunks) { c.Refresh(true); } }
private void TriangulateWithRiver( HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { Vector3 centerL, centerR; // Two cases: // If the cell has a river going through the opposite direction as well as the direction // that we are working with, the cell holds a straight river. if (cell.HasRiverThroughEdge(direction.Opposite())) { // Stretch the center into a line. Move 25% from the center to the first corner of the previous // direction, and 25% from the center to the second corner of the second direction. // One simple way of visualizing this is having a top-down view of the HexMesh and imagining // a triangulation in the eastern direction. centerL = center + HexMetrics.GetFirstSolidCorner(direction.Previous()) * 0.25f; centerR = center + HexMetrics.GetSecondSolidCorner(direction.Next()) * 0.25f; // Otherwise, the river does not flow in a straight line, check special cases: // Detect sharp turns by checking whether the cell has a rive going through the next // or previous cell part. // When there is a sharp turn, align the center line with the edge between this and the adjacent part. } else if (cell.HasRiverThroughEdge(direction.Next())) { centerL = center; centerR = Vector3.Lerp(center, e.v5, 2f / 3f /* Increased center line width from 1/2 to 2/3 */); } else if (cell.HasRiverThroughEdge(direction.Previous())) { centerL = Vector3.Lerp(center, e.v1, 2f / 3f /* Increased center line width from 1/2 to 2/3 */); centerR = center; // 2 step rotations, these produce gently curving rivers. // A river is going through two directions after this one. // Expand the center towards the center of the next direction's edge. } else if (cell.HasRiverThroughEdge(direction.Next2())) { centerL = center; // Note that the edge middle point is closer that the vertex itself (it's within the inner radius) // which is why extending the center towards that edge will end up with a pinched section. // We extend the center edge towards the middle edge times innerToOuter radius to keep // the channel width constant. centerR = center + HexMetrics.GetSolidEdgeMiddle(direction.Next()) * (0.5f * HexMetrics.innerToOuter); // 2 step rotation, a river is going through two directions before this one. } else { centerL = center + HexMetrics.GetSolidEdgeMiddle(direction.Previous()) * (0.5f * HexMetrics.innerToOuter); centerR = center; } // Determine the final center by averaging the Left and Right centers center = Vector3.Lerp(centerL, centerR, 0.5f); // We lerp the second and fourth vertices using 1/6 instead of the usual 1/4 as the // length from the edges is 1/8 instead of 1/4. This is because the channel has a // the same width along the river, so the relative edge length of the outer edges // will be 1/6 relative to the edge's middle length. (1/8 of 3/4) EdgeVertices m = new EdgeVertices( Vector3.Lerp(centerL, e.v1, 0.5f), Vector3.Lerp(centerR, e.v5, 0.5f), 1f / 6f); m.v3.y = center.y = e.v3.y; TriangulateEdgeStrip(m, cell.Color, e, cell.Color); // Add the triangles and quads that reached the center. terrain.AddTriangle(centerL, m.v1, m.v2); terrain.AddTriangleColor(cell.Color); terrain.AddQuad(centerL, center, m.v2, m.v3); terrain.AddQuadColor(cell.Color); terrain.AddQuad(center, centerR, m.v3, m.v4); terrain.AddQuadColor(cell.Color); terrain.AddTriangle(centerR, m.v4, m.v5); terrain.AddTriangleColor(cell.Color); if (!cell.IsUnderwater) { bool reversed = cell.IncomingRiver == direction; TriangulateRiverQuad(centerL, centerR, m.v2, m.v4, cell.RiverSurfaceY, 0.4f, reversed); TriangulateRiverQuad(m.v2, m.v4, e.v2, e.v4, cell.RiverSurfaceY, 0.6f, reversed); } }