void TriangulateConnection( HexDirection direction, HexCell cell, EdgeVertices e1 ) { HexCell neighbor = cell.GetNeighbor(direction); if (neighbor == null) { return; } Vector3 bridge = HexMetrics.GetBridge(direction); bridge.y = neighbor.Position.y - cell.Position.y; EdgeVertices e2 = new EdgeVertices( e1.v1 + bridge, e1.v4 + bridge ); if (cell.GetEdgeType(direction) == HexEdgeType.Slope) { TriangulateEdgeTerraces(e1, cell, e2, neighbor); } else { TriangulateEdgeStrip(e1, cell.color, e2, neighbor.color); } HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); if (direction <= HexDirection.E && nextNeighbor != null) { Vector3 v5 = e1.v4 + HexMetrics.GetBridge(direction.Next()); v5.y = nextNeighbor.Position.y; if (cell.Elevation <= neighbor.Elevation) { if (cell.Elevation <= nextNeighbor.Elevation) { TriangulateCorner( e1.v4, cell, e2.v4, neighbor, v5, nextNeighbor ); } else { TriangulateCorner( v5, nextNeighbor, e1.v4, cell, e2.v4, neighbor ); } } else if (neighbor.Elevation <= nextNeighbor.Elevation) { TriangulateCorner( e2.v4, neighbor, v5, nextNeighbor, e1.v4, cell ); } else { TriangulateCorner( v5, nextNeighbor, e1.v4, cell, e2.v4, neighbor ); } } }
void TriangulateConnection( HexDirection direction, HexCell cell, EdgeVertices e1) { HexCell neighbor = cell.GetNeighbor(direction); if (neighbor != null) { Vector3 bridge = HexMetrics.GetBridge(direction); bridge.y = neighbor.Position.y - cell.Position.y; EdgeVertices e2 = new EdgeVertices(e1.v1 + bridge, e1.v5 + bridge); if (cell.HasRiverThroughEdge(direction)) { e2.v3.y = neighbor.StreamBedY; if (!cell.IsUnderwater) { if (!neighbor.IsUnderwater) { TriangulateRiverQuad( e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbor.RiverSurfaceY, .8f, cell.HasIncomingRiver && cell.IncomingRiver == direction); } else if (cell.Elevation > neighbor.WaterLevel) { TriangulateWaterfallInWater( e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbor.RiverSurfaceY, neighbor.WaterSurfaceY); } } else if (!neighbor.IsUnderwater && neighbor.Elevation > cell.WaterLevel) { TriangulateWaterfallInWater( e2.v4, e2.v2, e1.v4, e1.v2, neighbor.RiverSurfaceY, cell.RiverSurfaceY, cell.WaterSurfaceY); } } if (cell.GetEdgeType(direction) == HexEdgeType.Slope) { TriangulateEdgeTerraces(e1, cell, e2, neighbor, cell.HasRoadThroughEdge(direction)); } else { TriangulateEdgeStrip(e1, cell.Color, e2, neighbor.Color, cell.HasRoadThroughEdge(direction)); } if (direction <= HexDirection.E) { HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); if (nextNeighbor != null) { Vector3 v5 = e1.v5 + HexMetrics.GetBridge(direction.Next()); v5.y = nextNeighbor.Position.y; if (cell.Elevation <= neighbor.Elevation) { if (cell.Elevation <= nextNeighbor.Elevation) { TriangulateCorner(e1.v5, cell, e2.v5, neighbor, v5, nextNeighbor); } else { TriangulateCorner(v5, nextNeighbor, e1.v5, cell, e2.v5, neighbor); } } else if (neighbor.Elevation <= nextNeighbor.Elevation) { TriangulateCorner(e2.v5, neighbor, v5, nextNeighbor, e1.v5, cell); } else { TriangulateCorner(v5, nextNeighbor, e1.v5, cell, e2.v5, neighbor); } } } } }
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, 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); 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 ); } }
//六边形之间的连接区域 void TriangulateConnection(HexDirection direction, HexCell cell, EdgeVertices e1) { HexCell neighbor = cell.GetNeighbor(direction); if (neighbor == null) { return; } //四边形外面2个顶点,bridge边 Vector3 bridge = HexMetrics.GetBridge(direction); bridge.y = neighbor.Position.y - cell.Position.y; //四边形bridge外面边 EdgeVertices e2 = new EdgeVertices( e1.v1 + bridge, e1.v5 + bridge ); bool hasRiver = cell.HasRiverThroughEdge(direction); bool hasRoad = cell.HasRoadThroughEdge(direction); /* * 如果方向上存在河流,则绘制河道 */ if (hasRiver) { e2.v3.y = neighbor.StreamBedY; if (!cell.IsUnderwater) { //river都不在水里 if (!neighbor.IsUnderwater) { TriangulateRiverQuad( e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbor.RiverSurfaceY, 0.8f, cell.HasIncomingRiver && cell.IncomingRiver == direction); } //river进入water,存在瀑布 else if (cell.Elevation > neighbor.WaterLevel) { TriangulateWaterfallInWater( e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbor.RiverSurfaceY, neighbor.WaterSurfaceY); } } //反过来,cell在水底,waterfall 方向向外 else if (!neighbor.IsUnderwater && neighbor.Elevation > cell.WaterLevel) { TriangulateWaterfallInWater( e2.v4, e2.v2, e1.v4, e1.v2, neighbor.RiverSurfaceY, cell.RiverSurfaceY, cell.WaterSurfaceY); } } /* * 根据不同连接边界类型 * 插值方式绘制三角形的边界bridge */ if (cell.GetEdgeType(direction) == HexEdgeType.Slope) { TriangulateEdgeTerraces(e1, cell, e2, neighbor, hasRoad); } else//Flat, Cliff情况 { TriangulateEdgeStrip(e1, color1, cell.TerrainTypeIndex, e2, color2, neighbor.TerrainTypeIndex, hasRoad); } //在connection区域加上围墙 features.AddWall(e1, cell, e2, neighbor, hasRiver, hasRoad); //被3个六边形共享的三角形区域 HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); if (direction <= HexDirection.E && nextNeighbor != null) { //添加Y轴 Vector3 v5 = e1.v5 + HexMetrics.GetBridge(direction.Next()); v5.y = nextNeighbor.Position.y; //如果当前cell是最低的, if (cell.Elevation <= neighbor.Elevation) { if (cell.Elevation <= nextNeighbor.Elevation) { TriangulateCorner(e1.v5, cell, e2.v5, neighbor, v5, nextNeighbor); } else {//内层判断失败,nextNeighbor最低,逆时针旋转三角形 TriangulateCorner(v5, nextNeighbor, e1.v5, cell, e2.v5, neighbor); } }//这么做是为了方便在TriangulateCorner方法中拓展 else if (neighbor.Elevation <= nextNeighbor.Elevation) { TriangulateCorner(e2.v5, neighbor, v5, nextNeighbor, e1.v5, cell); } else { TriangulateCorner(v5, nextNeighbor, e1.v5, cell, e2.v5, neighbor); } } }
private 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); var 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, 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); 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) { var 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 ); } }
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.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 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); } }
void TriangulateConnection(HexDirection direction, HexCell cell, EdgeVertices e1) { HexCell neighbor = cell.GetNeighbor(direction); if (neighbor == null) { return; } Vector3 bridge = HexMetrics.GetBridge(direction); bridge.y = neighbor.Position.y - cell.Position.y; EdgeVertices e2 = new EdgeVertices(e1.v1 + bridge, e1.v5 + bridge); if (cell.HasRiverThroughEdge(direction)) { e2.v3.y = neighbor.StreamBedY; TriangulateRiverQuad( e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbor.RiverSurfaceY, 0.8f, cell.HasIncomingRiver && cell.IncomingRiver == direction); } if (cell.GetEdgeType(direction) == HexEdgeType.Slope) { TriangulateEdgeTerraces(e1, cell, e2, neighbor); } else { TriangulateEdgeStrip(e1, color1, cell.TerrainTypeIndex, e2, color2, neighbor.TerrainTypeIndex); } HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); if (direction <= HexDirection.E && nextNeighbor != null) { Vector3 v5 = e1.v5 + HexMetrics.GetBridge(direction.Next()); v5.y = nextNeighbor.Position.y; //AddTriangle(v2, v4, v5); // AddTriangleColor(cell.Color, neighbor.Color, nextNeighbor.Color); if (cell.Elevation <= neighbor.Elevation) { if (cell.Elevation <= nextNeighbor.Elevation) { TriangulateCorner( e1.v5, cell, e2.v5, neighbor, v5, nextNeighbor); } else { TriangulateCorner( v5, nextNeighbor, e1.v5, cell, e2.v5, neighbor); } } else if (neighbor.Elevation <= nextNeighbor.Elevation) { TriangulateCorner( e2.v5, neighbor, v5, nextNeighbor, e1.v5, cell); } else { TriangulateCorner( v5, nextNeighbor, e1.v5, cell, e2.v5, neighbor); } } }
/// <summary> /// 三角化连接处 /// </summary> /// <param name="direction">处理的对应方向</param> /// <param name="cell">六边形对象引用</param> /// <param name="e1">边界中值插值对象</param> void TriangulateConnection( HexDirection direction, HexCell cell, EdgeVertices e1 ) { HexCell neighbor = cell.GetNeighbor(direction); // 防止边界网格过分填充 if (neighbor == null) { return; } Vector3 bridge = HexMetrics.GetBridge(direction); bridge.y = neighbor.Position.y - cell.Position.y; EdgeVertices e2 = new EdgeVertices( e1.v1 + bridge, e1.v5 + bridge ); // 设置边界河床高度 if (cell.HasRiverThroughEdge(direction)) { e2.v3.y = neighbor.StreamBedY; // 只在当前和相邻六边形都不在水下时添加河段, if (!cell.IsUnderwater) { if (!neighbor.IsUnderwater) { TriangulateRiverQuad( e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbor.RiverSurfaceY, 0.8f, cell.HasIncomingRiver && cell.IncomingRiver == direction ); } // 处理河面与水面交界处的情况 else if (cell.Elevation > neighbor.WaterLevel) { TriangulateWaterfallInWater( e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbor.RiverSurfaceY, neighbor.WaterSurfaceY ); } } // 相反方向的瀑布也要进行河道水面处理 else if (!neighbor.IsUnderwater && neighbor.Elevation > cell.WaterLevel) { TriangulateWaterfallInWater( e2.v4, e2.v2, e1.v4, e1.v2, neighbor.RiverSurfaceY, cell.RiverSurfaceY, cell.WaterSurfaceY ); } } // 限制坡度的细分阶梯数 if (cell.GetEdgeType(direction) == HexEdgeType.Slope) { TriangulateEdgeTerraces(e1, cell, e2, neighbor, cell.HasRoadThroughEdge(direction)); } else { TriangulateEdgeStrip(e1, cell.Color, e2, neighbor.Color, cell.HasRoadThroughEdge(direction)); } // 构造边界三角形 HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); if (direction <= HexDirection.E && nextNeighbor != null) { Vector3 v5 = e1.v5 + HexMetrics.GetBridge(direction.Next()); v5.y = nextNeighbor.Position.y; if (cell.Elevation <= neighbor.Elevation) { if (cell.Elevation <= nextNeighbor.Elevation) { TriangulateCorner( e1.v5, cell, e2.v5, neighbor, v5, nextNeighbor ); } else { TriangulateCorner( v5, nextNeighbor, e1.v5, cell, e2.v5, neighbor ); } } else if (neighbor.Elevation <= nextNeighbor.Elevation) { TriangulateCorner( e2.v5, neighbor, v5, nextNeighbor, e1.v5, cell ); } else { TriangulateCorner( v5, nextNeighbor, e1.v5, cell, e2.v5, neighbor ); } } }
/// <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); } }
/// <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 ); } }
private void TriangulateWaterShore(HexDirection direction, HexCell cell, HexCell neighbour, Vector3 centre) { var e1 = new EdgeVertices( centre + HexMetrics.GetFirstWaterCorner(direction), centre + HexMetrics.GetSecondWaterCorner(direction) ); Water.AddTriangle(centre, e1.v1, e1.v2); Water.AddTriangle(centre, e1.v2, e1.v3); Water.AddTriangle(centre, e1.v3, e1.v4); Water.AddTriangle(centre, e1.v4, e1.v5); var indices = new Vector3(cell.Index, neighbour.Index, cell.Index); Water.AddTriangleCellData(indices, weights1); Water.AddTriangleCellData(indices, weights1); Water.AddTriangleCellData(indices, weights1); Water.AddTriangleCellData(indices, weights1); var centre2 = neighbour.Position; if (neighbour.ColumnIndex < cell.ColumnIndex - 1) { centre2.x += HexMetrics.WrapSize * HexMetrics.InnerDiameter; } else if (neighbour.ColumnIndex > cell.ColumnIndex + 1) { centre2.x -= HexMetrics.WrapSize * HexMetrics.InnerDiameter; } centre2.y = centre.y; var e2 = new EdgeVertices( centre2 + HexMetrics.GetSecondSolidCorner(direction.Opposite()), centre2 + HexMetrics.GetFirstSolidCorner(direction.Opposite()) ); // rather than calculating from current centre, work backwards from neighbour centre to find edge 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); } var nextNeighbour = cell.GetNeighbour(direction.Next()); if (nextNeighbour == null) { return; } var centre3 = nextNeighbour.Position; if (nextNeighbour.ColumnIndex < cell.ColumnIndex - 1) { centre3.x += HexMetrics.WrapSize * HexMetrics.InnerDiameter; } else if (nextNeighbour.ColumnIndex > cell.ColumnIndex + 1) { centre3.x -= HexMetrics.WrapSize * HexMetrics.InnerDiameter; } var v3 = centre3 + (nextNeighbour.IsUnderwater ? HexMetrics.GetFirstWaterCorner(direction.Previous()) : HexMetrics.GetFirstSolidCorner(direction.Previous())); v3.y = centre.y; WaterShore.AddTriangle(e1.v5, e2.v5, v3); WaterShore.AddTriangleUV( new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, nextNeighbour.IsUnderwater ? 0f : 1f)); indices.z = nextNeighbour.Index; WaterShore.AddTriangleCellData(indices, weights1, weights2, weights3); }
private void TriangulateRoadAdjacentToRiver(HexDirection direction, HexCell cell, Vector3 centre, EdgeVertices e) { var edgeRoad = cell.HasRoadThroughEdge(direction); var previousRiver = cell.HasRiverThroughEdge(direction.Previous()); var nextRiver = cell.HasRiverThroughEdge(direction.Next()); var interpolators = GetRoadInterpolators(direction, cell); var roadCentre = centre; if (cell.HasRiverBeginOrEnd) // pointy end of rivers { roadCentre += HexMetrics.GetSolidEdgeMiddle(cell.RiverBeginOrEndDirection.Opposite()) * 1f / 3; } else if (cell.IncomingRiver == cell.OutgoingRiver.Opposite()) // straight rivers { Vector3 corner; if (previousRiver) { if (!edgeRoad && !cell.HasRoadThroughEdge(direction.Next())) { return; // isolated on one side of the river } corner = HexMetrics.GetSecondSolidCorner(direction); } else { if (!edgeRoad && !cell.HasRoadThroughEdge(direction.Previous())) { return; // isolated on one side of the river } corner = HexMetrics.GetFirstSolidCorner(direction); } roadCentre += corner / 2; if (cell.IncomingRiver == direction.Next() && (cell.HasRoadThroughEdge(direction.Next2()) || cell.HasRoadThroughEdge(direction.Opposite()))) { Features.AddBridge(roadCentre, centre - corner / 2); } centre += corner / 4; } else if (cell.IncomingRiver == cell.OutgoingRiver.Previous()) // zigzag river orientation 1 { roadCentre -= HexMetrics.GetSecondSolidCorner(cell.IncomingRiver) * 0.2f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Next()) // zigzag river orientation 2 { roadCentre -= HexMetrics.GetFirstSolidCorner(cell.IncomingRiver) * 0.2f; } else if (previousRiver && nextRiver) // inside of curved river { if (!edgeRoad) { return; // isolated road - i.e road didn't come from this edge, and doesn't connect out either. } var offset = HexMetrics.GetSolidEdgeMiddle(direction) * HexMetrics.InnerToOuter; roadCentre += offset * 0.7f; centre += offset / 2; } else // outside of curved river { HexDirection middle; if (previousRiver) { middle = direction.Next(); } else if (nextRiver) { middle = direction.Previous(); } else { middle = direction; } if (!cell.HasRoadThroughEdge(middle) && !cell.HasRoadThroughEdge(middle.Previous()) && !cell.HasRoadThroughEdge(middle.Next())) { return; // prune orphaned rivers on the inside of a curve } var offset = HexMetrics.GetSolidEdgeMiddle(middle); roadCentre += offset / 4; if (direction == middle && cell.HasRoadThroughEdge(direction.Opposite())) { Features.AddBridge(roadCentre, centre - offset * (HexMetrics.InnerToOuter * 0.7f)); } } var ml = Vector3.Lerp(roadCentre, e.v1, interpolators.x); var mr = Vector3.Lerp(roadCentre, e.v5, interpolators.y); TriangulateRoad(roadCentre, ml, mr, e, edgeRoad, cell.Index); if (previousRiver) { TriangulateRoadEdge(roadCentre, centre, ml, cell.Index); } if (nextRiver) { TriangulateRoadEdge(roadCentre, mr, centre, cell.Index); } }
private void TriangulateConnection(HexDirection direction, HexCell cell, EdgeVertices e1) { var neighbour = cell.GetNeighbour(direction); if (neighbour == null) { return; // dont add for edge hexes } var bridge = HexMetrics.GetBridge(direction); bridge.y = neighbour.Position.y - cell.Position.y; var e2 = new EdgeVertices( e1.v1 + bridge, e1.v5 + bridge ); var hasRiver = cell.HasRiverThroughEdge(direction); var hasRoad = cell.HasRoadThroughEdge(direction); if (hasRiver) { var startV3 = e2.v3.y; e2.v3.y = neighbour.StreamBedY; var indices = new Vector3(cell.Index, neighbour.Index, cell.Index); // by definition, both cells have rivers through them // however, if both are underwater, then we want (i want) no river bed // if only one is, the river should merge with the stream // EXCEPT if there is an elevation difference, in which case we need the stream bed to make a waterfall // if im a river and the neighbour is a river if (!cell.IsUnderwater && !neighbour.IsUnderwater) { TriangulateRiverQuad( e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbour.RiverSurfaceY, 0.8f, cell.HasIncomingRiver && cell.IncomingRiver == direction, indices); } // if im a river and the neighbour is beneath me else if (!cell.IsUnderwater && cell.Elevation > neighbour.WaterLevel) { TriangulateWaterfallInWater( e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbour.RiverSurfaceY, neighbour.WaterLevel, indices); } // im underwater but the neighbour is heigher than me else if (cell.IsUnderwater && !neighbour.IsUnderwater && neighbour.Elevation > cell.WaterLevel) { TriangulateWaterfallInWater( e2.v4, e2.v2, e1.v4, e1.v2, neighbour.RiverSurfaceY, cell.RiverSurfaceY, cell.WaterLevel, indices); } else if ((cell.IsUnderwater == neighbour.IsUnderwater == true) || // both underwater !cell.IsUnderwater && neighbour.IsUnderwater) // river into water on same level { e2.v3.y = startV3; // if a river, this will smooth e1 (river side) into e2 (lake/sea bed, which is normal surface) } // if not a river, then e1 is already sea/lake bed, so e2 will now be approximate same level } if (HexMetrics.GetEdgeType(cell.Elevation, neighbour.Elevation) == HexEdgeType.Slope) { TriangulateEdgeTerrace(e1, cell, e2, neighbour, hasRoad); } else { TriangulateEdgeStrip(e1, weights1, cell.Index, e2, weights2, neighbour.Index, hasRoad); } Features.AddWall(e1, cell, e2, neighbour, hasRiver, hasRoad); if (direction > HexDirection.E) { return; } var nextDirection = direction.Next(); var nextNeighbour = cell.GetNeighbour(nextDirection); if (nextNeighbour == null) { return; } var v5 = e1.v5 + HexMetrics.GetBridge(nextDirection); v5.y = nextNeighbour.Position.y; var minElevation = Mathf.Min(cell.Elevation, neighbour.Elevation, nextNeighbour.Elevation); if (minElevation == cell.Elevation) { TriangulateCorner(e1.v5, cell, e2.v5, neighbour, v5, nextNeighbour); } else if (minElevation == neighbour.Elevation) { TriangulateCorner(e2.v5, neighbour, v5, nextNeighbour, e1.v5, cell); } else { TriangulateCorner(v5, nextNeighbour, e1.v5, cell, e2.v5, neighbour); } }
/// <summary> /// 三角化桥、角落以及桥中间的河水 /// </summary> /// <param name="direction">生成方向</param> /// <param name="cell">自身六边形</param> /// <param name="e1">双色混合区靠近圆心的边</param> void TriangulateConnection(HexDirection direction, HexCell cell, EdgeVertices e1) { // 对应方向上的邻居 HexCell neighbor = cell.GetNeighbor(direction); // "??"表示如果前者为空则使用后者 ,a ?? b是 a != null ? a : b的简写 // 如果没有邻居则不需要连接桥 if (neighbor == null) { return; } // 临近六边形索引 Vector3 indices; indices.x = indices.z = cell.Index; indices.y = neighbor.Index; Vector3 bridge = HexMetrics.GetBridge(direction); Vector3 e2_v1 = e1.v1 + bridge; Vector3 e2_v5 = e1.v5 + bridge; e2_v1.y = e2_v5.y = neighbor.Position.y; // 由于对y方向进行了噪声扰乱,所以这里直接取高度,不能在用neighbor.Elevation * HexMetrics.elevationStep计算了 EdgeVertices e2 = new EdgeVertices(e2_v1, e2_v5); bool hasRiver = cell.HasRiverThroughEdge(direction); // 对应方向是否有河流 bool hasRoad = cell.HasRoadThroughEdge(direction); // 对应方向是否有路 // 如果六边形对应方向有河流,则调整桥邻居一侧的中心顶点的高度(自身在三角化六边形三角面的时候已经调整过了(Triangulate方法里调整的)) if (hasRiver) { e2.v3.y = neighbor.StreamBedY; } ///// 桥混合区 if (cell.GetEdgeType(direction) == HexEdgeType.Slope) { // 生成阶梯 TriangulateEdgeTerraces(e1, cell, e2, neighbor, hasRoad); } else { // 生成斜面 TriangulateEdgeStrip(e1, weights1, cell.Index, e2, weights2, neighbor.Index, hasRoad); } ///// 桥混合区end // 围墙 features.AddWall(e1, cell, e2, neighbor, hasRiver, hasRoad); //// 三角混合区(角落) HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); // 每个六边形只需要生成两个三角(东北桥右侧三角、东桥下侧三角),因为三个六边形共享一个三角混合区, // 如果没有下一个邻居则不需要生成三角 if (direction <= HexDirection.E && nextNeighbor != null) { Vector3 nextDirectionV3 = e1.v5 + HexMetrics.GetBridge(direction.Next()); nextDirectionV3.y = nextNeighbor.Position.y; //nextNeighbor.Elevation * HexMetrics.elevationStep; // 找出最矮的六边形,赋值不同的参数,以便于分类处理所有情况 if (cell.Elevation <= neighbor.Elevation) { if (cell.Elevation <= nextNeighbor.Elevation) { TriangulateCorner(e1.v5, cell, e2.v5, neighbor, nextDirectionV3, nextNeighbor); } else { TriangulateCorner(nextDirectionV3, nextNeighbor, e1.v5, cell, e2.v5, neighbor); } } else if (neighbor.Elevation <= nextNeighbor.Elevation) { TriangulateCorner(e2.v5, neighbor, nextDirectionV3, nextNeighbor, e1.v5, cell); } else { TriangulateCorner(nextDirectionV3, nextNeighbor, e1.v5, cell, e2.v5, neighbor); } } //// 三角混合区(角落)End // 判断是否有河流流过,如果有则三角化桥中间的河水 if (cell.HasRiverThroughEdge(direction)) { e2.v3.y = neighbor.StreamBedY; // 判断自己是否是陆地 if (!cell.IsUnderwater) { // 判断邻居是否是陆地 if (!neighbor.IsUnderwater) { TriangulateRiverQuad(e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbor.RiverSurfaceY, 0.8f, cell.HasIncomingRiver && cell.IncomingRiver == direction, indices ); } else { // 三角化瀑布 TriangulateWaterfallInWater(e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbor.RiverSurfaceY, neighbor.WaterSurfaceY, indices); } } // 如果自己在水下,邻居是陆地 else if (!neighbor.IsUnderwater && neighbor.Elevation > cell.WaterLevel) { // 三角化瀑布 TriangulateWaterfallInWater(e2.v4, e2.v2, e1.v4, e1.v2, neighbor.RiverSurfaceY, cell.RiverSurfaceY, cell.WaterSurfaceY, indices); } } }
public bool IsSmoothCorner(HexDirection direction) { if (HasBuilding(direction.Previous()) && !HasBuilding(direction) && HasBuilding(direction.Next())) { return(true); } return(false); }
/// <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); } }
/// <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 TriangulateConnection( HexDirection direction, HexCell cell, EdgeVertices e1 ) { var neighbor = cell.GetNeighbor(direction); if (neighbor == null) { return; } var bridge = HexMetrics.GetBridge(direction); bridge.y = neighbor.Position.y - cell.Position.y; var e2 = new EdgeVertices( e1.v1 + bridge, e1.v5 + bridge ); var hasRiver = cell.HasRiverThroughEdge(direction); var hasRoad = cell.HasRoadThroughEdge(direction); if (hasRiver) { e2.v3.y = neighbor.StreamBedY; Vector3 indices; indices.x = indices.z = cell.Index; indices.y = neighbor.Index; if (!cell.IsUnderwater) { if (!neighbor.IsUnderwater) { TriangulateRiverQuad( e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbor.RiverSurfaceY, 0.8f, cell.HasIncomingRiver && cell.IncomingRiver == direction, indices ); } else if (cell.Elevation > neighbor.WaterLevel) { TriangulateWaterfallInWater( e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbor.RiverSurfaceY, neighbor.WaterSurfaceY, indices ); } } else if ( !neighbor.IsUnderwater && neighbor.Elevation > cell.WaterLevel ) { TriangulateWaterfallInWater( e2.v4, e2.v2, e1.v4, e1.v2, neighbor.RiverSurfaceY, cell.RiverSurfaceY, cell.WaterSurfaceY, indices ); } } if (cell.GetEdgeType(direction) == HexEdgeType.Slope) { TriangulateEdgeTerraces(e1, cell, e2, neighbor, hasRoad); } else { TriangulateEdgeStrip( e1, weights1, cell.Index, e2, weights2, neighbor.Index, hasRoad ); } features.AddWall(e1, cell, e2, neighbor, hasRiver, hasRoad); var nextNeighbor = cell.GetNeighbor(direction.Next()); if (direction <= HexDirection.E && nextNeighbor != null) { var v5 = e1.v5 + HexMetrics.GetBridge(direction.Next()); v5.y = nextNeighbor.Position.y; if (cell.Elevation <= neighbor.Elevation) { if (cell.Elevation <= nextNeighbor.Elevation) { TriangulateCorner( e1.v5, cell, e2.v5, neighbor, v5, nextNeighbor ); } else { TriangulateCorner( v5, nextNeighbor, e1.v5, cell, e2.v5, neighbor ); } } else if (neighbor.Elevation <= nextNeighbor.Elevation) { TriangulateCorner( e2.v5, neighbor, v5, nextNeighbor, e1.v5, cell ); } else { TriangulateCorner( v5, nextNeighbor, e1.v5, cell, e2.v5, neighbor ); } } }
private void TriangulateWaterShore(HexDirection dir, HexCell cell, HexCell neighbor, Vector3 center) { var e1 = new EdgeVertices( center + HexMetrics.GetFirstWaterCorner(dir), center + HexMetrics.GetSecondWaterCorner(dir) ); 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); var indices = new Vector3(cell.Index, neighbor.Index, cell.Index); water.AddTriangleCellData(indices, weights1); water.AddTriangleCellData(indices, weights1); water.AddTriangleCellData(indices, weights1); water.AddTriangleCellData(indices, weights1); var 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; var e2 = new EdgeVertices( center2 + HexMetrics.GetSecondSolidCorner(dir.Opposite()), center2 + HexMetrics.GetFirstSolidCorner(dir.Opposite()) ); if (cell.HasRiverThroughEdge(dir)) { TriangulateEstuary(e1, e2, cell.HasIncomingRiver && cell.IncomingRiver == dir, 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); } var nextNeighbor = cell.GetNeighbor(dir.Next()); if (nextNeighbor != null) { var 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; } var v3 = center3 + (nextNeighbor.IsUnderwater ? HexMetrics.GetFirstWaterCorner(dir.Previous()) : HexMetrics.GetFirstSolidCorner(dir.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); } }
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; 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; 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.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); } }
private void TriangulateRoadAdjacentToRiver(HexDirection dir, HexCell cell, Vector3 center, EdgeVertices e) { var hasRoadThroughEdge = cell.HasRoadThroughEdge(dir); var previousHasRiver = cell.HasRiverThroughEdge(dir.Previous()); var nextHasRiver = cell.HasRiverThroughEdge(dir.Next()); var interpolators = GetRoadInterpolators(dir, cell); var 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(dir.Next())) { return; } corner = HexMetrics.GetSecondSolidCorner(dir); } else { if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(dir.Previous())) { return; } corner = HexMetrics.GetFirstSolidCorner(dir); } roadCenter += corner * .5f; if (cell.IncomingRiver == dir.Next() && (cell.HasRoadThroughEdge(dir.Next2()) || cell.HasRoadThroughEdge(dir.Opposite()))) { features.AddBridge(roadCenter, center - corner * .5f); } center += corner * .25f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Previous()) { roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiver) * .2f; } else if (cell.IncomingRiver == cell.OutgoingRiver.Next()) { roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiver) * .2f; } else if (previousHasRiver && nextHasRiver) { if (!hasRoadThroughEdge) { return; } var offset = HexMetrics.GetSolidEdgeMiddle(dir) * HexMetrics.innerToOuter; roadCenter += offset * .7f; center += offset * .5f; } else { HexDirection middle; if (previousHasRiver) { middle = dir.Next(); } else if (nextHasRiver) { middle = dir.Previous(); } else { middle = dir; } if (!cell.HasRoadThroughEdge(middle) && !cell.HasRoadThroughEdge(middle.Previous()) && !cell.HasRoadThroughEdge(middle.Next()) ) { return; } var offset = HexMetrics.GetSolidEdgeMiddle(middle); roadCenter += offset * .25f; if (dir == middle && cell.HasRoadThroughEdge(dir.Opposite())) { features.AddBridge(roadCenter, center - offset * (HexMetrics.innerToOuter * .7f)); } } var mL = Vector3.Lerp(roadCenter, e.v1, interpolators.x); var mR = Vector3.Lerp(roadCenter, e.v5, interpolators.y); TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge, cell.Index); if (cell.HasRiverThroughEdge(dir.Previous())) { TriangulateRoadEdge(roadCenter, center, mL, cell.Index); } if (cell.HasRiverThroughEdge(dir.Next())) { TriangulateRoadEdge(roadCenter, mR, center, cell.Index); } }
/// <summary> /// Триангуляция соединения между клетками /// </summary> /// <param name="direction"></param> /// <param name="cell"></param> /// <param name="e1"></param> void TriangulateConnection(HexDirection direction, HexCell cell, EdgeVertices e1) { HexCell neighbor = cell.GetNeighbor(direction); if (neighbor == null) { return; } Vector3 bridge = HexMetrics.GetBridge(direction); bridge.y = neighbor.Position.y - cell.Position.y; EdgeVertices e2 = new EdgeVertices( e1.v1 + bridge, e1.v5 + bridge ); bool hasRiver = cell.HasRiverThroughEdge(direction); bool hasRoad = cell.HasRoadThroughEdge(direction); if (hasRiver)//реки на соединениях { e2.v3.y = neighbor.StreamBedY; Vector3 indices; indices.x = indices.z = cell.Index; indices.y = neighbor.Index; if (!cell.IsUnderwater) { if (!neighbor.IsUnderwater) { TriangulateRiverQuad( e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbor.RiverSurfaceY, 0.8f, cell.HasIncomingRiver && cell.IncomingRiver == direction, indices ); } else if (cell.Elevation > neighbor.WaterLevel) { TriangulateWaterfallInWater( e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbor.RiverSurfaceY, neighbor.WaterSurfaceY, indices ); } } else if ( !neighbor.IsUnderwater && neighbor.Elevation > cell.WaterLevel ) { TriangulateWaterfallInWater( e2.v4, e2.v2, e1.v4, e1.v2, neighbor.RiverSurfaceY, cell.RiverSurfaceY, cell.WaterSurfaceY, indices ); } } if (cell.GetEdgeType(direction) == HexEdgeType.Slope) { TriangulateEdgeTerraces(e1, cell, e2, neighbor, hasRoad); } else { TriangulateEdgeStrip( e1, weights1, cell.Index, e2, weights2, neighbor.Index, hasRoad ); } features.AddWall(e1, cell, e2, neighbor, hasRiver, hasRoad); HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); if (direction <= HexDirection.E && nextNeighbor != null) { Vector3 v5 = e1.v5 + HexMetrics.GetBridge(direction.Next()); v5.y = nextNeighbor.Position.y; if (cell.Elevation <= neighbor.Elevation)//условия, чтобы знать, какая ячейка ниже(нужно, чтобы определить тип угла) { if (cell.Elevation <= nextNeighbor.Elevation) { TriangulateCorner(e1.v5, cell, e2.v5, neighbor, v5, nextNeighbor); } else { TriangulateCorner(v5, nextNeighbor, e1.v5, cell, e2.v5, neighbor); } } else { if (neighbor.Elevation <= nextNeighbor.Elevation) { TriangulateCorner(e2.v5, neighbor, v5, nextNeighbor, e1.v5, cell); } else { TriangulateCorner(v5, nextNeighbor, e1.v5, cell, e2.v5, neighbor); } } } }
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); } } }
//绘制河道贯穿的整个cell的情况 void TriangulateWithRiver( HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { Vector3 centerL, centerR; if (cell.HasRiverThroughEdge(direction.Opposite())) { //河流中心的左右岸,*0.25是因为边界是4个矩形,河流占0.5 centerL = center + HexMetrics.GetFirstSolidCorner(direction.Previous()) * 0.25f; centerR = center + HexMetrics.GetSecondSolidCorner(direction.Next()) * 0.25f; } //当cell河流存在转角的时候 else if (cell.HasRiverThroughEdge(direction.Previous())) { centerR = center; centerL = Vector3.Lerp(center, e.v1, 2f / 3f); } else if (cell.HasRiverThroughEdge(direction.Next())) { centerL = center; centerR = Vector3.Lerp(center, e.v5, 2f / 3f); } 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, color1, cell.TerrainTypeIndex, e, color1, cell.TerrainTypeIndex); //添加三角形面片 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); //顺序添加顶点颜色 terrain.AddTriangleColor(color1); terrain.AddQuadColor(color1); terrain.AddQuadColor(color1); terrain.AddTriangleColor(color1); //地形贴图索引 Vector3 types; types.x = types.y = types.z = cell.TerrainTypeIndex; terrain.AddTriangleTerrainTypes(types); terrain.AddQuadTerrainTypes(types); terrain.AddQuadTerrainTypes(types); terrain.AddTriangleTerrainTypes(types); 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); } }
public void TriangulateConnection(HexDirection dir, HexCell cell, EdgeVertices edges) { HexCell neighbour = cell.GetNeighbour(dir); if (neighbour == null) { return; } Vector3 bridge = HexMetrics.GetBridge(dir); bridge.y = neighbour.Position.y - cell.Position.y; EdgeVertices edges2 = new EdgeVertices(edges.v1 + bridge, edges.v5 + bridge); bool hasRoad = cell.HasRoadThroughEdge(dir); bool hasRiver = cell.HasRiverThroughEdge(dir); if (hasRiver) { edges2.v3.y = neighbour.StreamBedY; Vector3 indices = new Vector3(cell.CellIndex, neighbour.CellIndex, cell.CellIndex); if (!cell.IsUnderwater) { if (!neighbour.IsUnderwater) { bool reverse = cell.HasIncomingRiver && cell.IncomingRiverDirection == dir; TriangulateRiverQuad(edges.v2, edges.v4, edges2.v2, edges2.v4, cell.RiverSurfaceY, neighbour.RiverSurfaceY, 0.8f, reverse, indices); } else if (cell.Elevation > neighbour.WaterLevel) { TriangulateWaterfallInWater(edges.v2, edges.v4, edges2.v2, edges2.v4, cell.RiverSurfaceY, neighbour.RiverSurfaceY, neighbour.WaterSurfaceY, indices); } } else if (!neighbour.IsUnderwater && neighbour.Elevation > cell.WaterLevel) { TriangulateWaterfallInWater(edges2.v2, edges2.v4, edges.v2, edges.v4, neighbour.RiverSurfaceY, cell.RiverSurfaceY, cell.WaterSurfaceY, indices); } } if (cell.GetEdgeType(dir) == HexEdgeType.Slope) { TriangulateEdgeTerraces(edges, cell, edges2, neighbour, hasRoad); } else { TriangulateEdgeStrip(edges, Weights1, cell.CellIndex, edges2, Weights2, neighbour.CellIndex, hasRoad); } FeatureManager.AddWall(edges, cell, edges2, neighbour, hasRoad, hasRiver); HexCell nextNeighbor = cell.GetNeighbour(dir.Next()); if (dir <= HexDirection.E && nextNeighbor != null) { Vector3 v5 = edges.v5 + HexMetrics.GetBridge(dir.Next()); v5.y = nextNeighbor.Position.y; if (cell.Elevation <= neighbour.Elevation) { if (cell.Elevation < nextNeighbor.Elevation) { TriangulateCorner(edges.v5, cell, edges2.v5, neighbour, v5, nextNeighbor); } else { TriangulateCorner(v5, nextNeighbor, edges.v5, cell, edges2.v5, neighbour); } } else if (neighbour.Elevation < nextNeighbor.Elevation) { TriangulateCorner(edges2.v5, neighbour, v5, nextNeighbor, edges.v5, cell); } else { TriangulateCorner(v5, nextNeighbor, edges.v5, cell, edges2.v5, neighbour); } } }
private 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, 0.5f); } else if (cell.HasRiverThroughEdge(direction.Previous())) { centerL = Vector3.Lerp(center, e.v1, 0.5f); 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, .4f, reversed); TriangulateRiverQuad(m.v2, m.v4, e.v2, e.v4, cell.RiverSurfaceY, .6f, reversed); } }
public void TriangulateRoadsAdjacentToRiver(HexDirection dir, HexCell cell, Vector3 center, EdgeVertices edges) { bool hasRoadThroughEdge = cell.HasRoadThroughEdge(dir); bool previousHasRiver = cell.HasRiverThroughEdge(dir.Previous()); bool nextHasRiver = cell.HasRiverThroughEdge(dir.Next()); Vector2 roadInterpolators = GetRoadInterpolators(dir, cell); Vector3 roadCenter = center; if (cell.HasRiverBeginningOrEnd) { roadCenter += HexMetrics.GetSolidEdgeMiddle(cell.RiverBeginOrEndDirection.Opposite()) * (1f / 3f); } else if (cell.IncomingRiverDirection == cell.OutgoingRiverDirection.Opposite()) { Vector3 corner; if (previousHasRiver) { if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(dir.Next())) { return; } corner = HexMetrics.GetSecondSolidCorner(dir); } else { if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(dir.Previous())) { return; } corner = HexMetrics.GetFirstSolidCorner(dir); } roadCenter += corner * 0.5f; if (cell.IncomingRiverDirection == dir.Next() && (cell.HasRoadThroughEdge(dir.Next2()) || cell.HasRoadThroughEdge(dir.Opposite()))) { FeatureManager.AddBridge(roadCenter, center - corner * 0.5f); } center += corner * 0.25f; } else if (cell.IncomingRiverDirection == cell.OutgoingRiverDirection.Previous()) { roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiverDirection) * 0.2f; } else if (cell.IncomingRiverDirection == cell.OutgoingRiverDirection.Next()) { roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiverDirection) * 0.2f; } else if (previousHasRiver && nextHasRiver) { if (!hasRoadThroughEdge) { return; } Vector3 offset = HexMetrics.GetSolidEdgeMiddle(dir) * HexMetrics.InnerToOuter; roadCenter += offset * 0.7f; center += offset * 0.5f; } else { HexDirection middle; if (previousHasRiver) { middle = dir.Next(); } else if (nextHasRiver) { middle = dir.Previous(); } else { middle = dir; } if (!cell.HasRoadThroughEdge(middle) && !cell.HasRoadThroughEdge(middle.Previous()) && !cell.HasRoadThroughEdge(middle.Next())) { return; } Vector3 offset = HexMetrics.GetSolidEdgeMiddle(middle); roadCenter += offset * 0.25f; if (dir == middle && cell.HasRoadThroughEdge(dir.Opposite())) { FeatureManager.AddBridge(roadCenter, center - offset * (HexMetrics.InnerToOuter * 0.7f)); } } Vector3 mL = Vector3.Lerp(center, edges.v1, roadInterpolators.x); Vector3 mR = Vector3.Lerp(center, edges.v5, roadInterpolators.y); TriangulateRoad(roadCenter, mL, mR, edges, hasRoadThroughEdge, cell.CellIndex); if (previousHasRiver) { TriangulateRoadEdge(roadCenter, center, mL, cell.CellIndex); } if (nextHasRiver) { TriangulateRoadEdge(roadCenter, mR, center, cell.CellIndex); } }
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; } 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); if (previousHasRiver) { TriangulateRoadEdge(roadCenter, center, mL); } if (nextHasRiver) { TriangulateRoadEdge(roadCenter, mR, center); } }
void TriangulateConnection( HexDirection direction, HexCell cell, Vector3 v1, Vector3 v2 ) { HexCell neighbor = cell.GetNeighbor(direction); if (neighbor == null) { return; } Vector3 bridge = HexMetrics.GetBridge(direction); Vector3 v3 = v1 + bridge; Vector3 v4 = v2 + bridge; v3.y = v4.y = neighbor.Elevation * HexMetrics.elevationStep; if (cell.GetEdgeType(direction) == HexEdgeType.Slope) { TriangulateEdgeTerraces(v1, v2, cell, v3, v4, neighbor); } else { AddQuad(v1, v2, v3, v4); AddQuadColor(cell.color, neighbor.color); } HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); if (direction <= HexDirection.E && nextNeighbor != null) { Vector3 v5 = v2 + HexMetrics.GetBridge(direction.Next()); v5.y = nextNeighbor.Elevation * HexMetrics.elevationStep; if (cell.Elevation <= neighbor.Elevation) { if (cell.Elevation <= nextNeighbor.Elevation) { TriangulateCorner(v2, cell, v4, neighbor, v5, nextNeighbor); } else { TriangulateCorner(v5, nextNeighbor, v2, cell, v4, neighbor); } } else if (neighbor.Elevation <= nextNeighbor.Elevation) { TriangulateCorner(v4, neighbor, v5, nextNeighbor, v2, cell); } else { TriangulateCorner(v5, nextNeighbor, v2, cell, v4, neighbor); } } }