Example #1
0
    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
                    );
            }
        }
    }
Example #2
0
    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);
                    }
                }
            }
        }
    }
Example #3
0
    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
                );
        }
    }
Example #4
0
    //六边形之间的连接区域
    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);
            }
        }
    }
Example #5
0
        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
                    );
            }
        }
Example #6
0
    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
                );
        }
    }
Example #7
0
    /// <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);
        }
    }
Example #8
0
    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);
            }
        }
    }
Example #9
0
    /// <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
                    );
            }
        }
    }
Example #10
0
    /// <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);
        }
    }
Example #11
0
    /// <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);
            }
        }
Example #15
0
    /// <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);
            }
        }
    }
Example #16
0
 public bool IsSmoothCorner(HexDirection direction)
 {
     if (HasBuilding(direction.Previous()) && !HasBuilding(direction) && HasBuilding(direction.Next()))
     {
         return(true);
     }
     return(false);
 }
Example #17
0
    /// <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);
        }
    }
Example #18
0
    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);
        }
    }
Example #19
0
    /// <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);
        }
    }
Example #20
0
        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
                        );
                }
            }
        }
Example #21
0
    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);
        }
    }
Example #22
0
    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);
        }
    }
Example #23
0
    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);
        }
    }
Example #24
0
    /// <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);
            }
        }
    }
Example #26
0
    //绘制河道贯穿的整个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);
            }
        }
    }
Example #28
0
    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);
        }
    }
Example #31
0
    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);
            }
        }
    }