Example #1
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)
    {
        EdgeVertices e1 = new EdgeVertices(
            center + HexMetrics.GetFirstWaterCorner(direction),
            center + HexMetrics.GetSecondWaterCorner(direction)
            );

        water.AddTriangle(center, e1.v1, e1.v2);
        water.AddTriangle(center, e1.v2, e1.v3);
        water.AddTriangle(center, e1.v3, e1.v4);
        water.AddTriangle(center, e1.v4, e1.v5);
        Vector3 indices;

        //indices.x = indices.y = indices.z = cell.Index;
        indices.x = indices.z = cell.Index;
        indices.y = neighbor.Index;
        water.AddTriangleCellData(indices, weights1);
        water.AddTriangleCellData(indices, weights1);
        water.AddTriangleCellData(indices, weights1);
        water.AddTriangleCellData(indices, weights1);

        //Vector3 bridge = HexMetrics.GetWaterBridge(direction);
        Vector3 center2 = neighbor.Position;

        if (neighbor.ColumnIndex < cell.ColumnIndex - 1)
        {
            center2.x += HexMetrics.wrapSize * HexMetrics.innerDiameter;
        }
        else if (neighbor.ColumnIndex > cell.ColumnIndex + 1)
        {
            center2.x -= HexMetrics.wrapSize * HexMetrics.innerDiameter;
        }
        center2.y = center.y;
        EdgeVertices e2 = new EdgeVertices(
            center2 + HexMetrics.GetSecondSolidCorner(direction.Opposite()),
            center2 + HexMetrics.GetFirstSolidCorner(direction.Opposite())
            );

        if (cell.HasRiverThroughEdge(direction))
        {
            TriangulateEstuary(e1, e2, cell.HasIncomingRiver && cell.IncomingRiver == direction, indices);
        }
        else
        {
            waterShore.AddQuad(e1.v1, e1.v2, e2.v1, e2.v2);
            waterShore.AddQuad(e1.v2, e1.v3, e2.v2, e2.v3);
            waterShore.AddQuad(e1.v3, e1.v4, e2.v3, e2.v4);
            waterShore.AddQuad(e1.v4, e1.v5, e2.v4, e2.v5);
            waterShore.AddQuadUV(0f, 0f, 0f, 1f);
            waterShore.AddQuadUV(0f, 0f, 0f, 1f);
            waterShore.AddQuadUV(0f, 0f, 0f, 1f);
            waterShore.AddQuadUV(0f, 0f, 0f, 1f);
            waterShore.AddQuadCellData(indices, weights1, weights2);
            waterShore.AddQuadCellData(indices, weights1, weights2);
            waterShore.AddQuadCellData(indices, weights1, weights2);
            waterShore.AddQuadCellData(indices, weights1, weights2);
        }

        HexCell nextNeighbor = cell.GetNeighbor(direction.Next());

        if (nextNeighbor != null)
        {
            //Vector3 center3 = nextNeighbor.Position;
            //center3.y = center.y;
            Vector3 center3 = nextNeighbor.Position;
            if (nextNeighbor.ColumnIndex < cell.ColumnIndex - 1)
            {
                center3.x += HexMetrics.wrapSize * HexMetrics.innerDiameter;
            }
            else if (nextNeighbor.ColumnIndex > cell.ColumnIndex + 1)
            {
                center3.x -= HexMetrics.wrapSize * HexMetrics.innerDiameter;
            }
            Vector3 v3 = center3 + (nextNeighbor.IsUnderwater ?
                                    HexMetrics.GetFirstWaterCorner(direction.Previous()) :
                                    HexMetrics.GetFirstSolidCorner(direction.Previous())
                                    );
            v3.y = center.y;
            waterShore.AddTriangle(e1.v5, e2.v5, v3);
            waterShore.AddTriangulateUV(new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, nextNeighbor.IsUnderwater ? 0f : 1f));
            indices.z = nextNeighbor.Index;
            waterShore.AddTriangleCellData(indices, weights1, weights2, weights3);
        }
    }
Example #2
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);
        TriangulateEdgeStrip(m, weights1, cell.Index, e, weights1, cell.Index);

        terrain.AddTriangle(centerL, m.v1, m.v2);
        //terrain.AddTriangleColor(cell.Color);
        terrain.AddQuad(centerL, center, m.v2, m.v3);
        //terrain.AddQuadColor(cell.Color);
        terrain.AddQuad(center, centerR, m.v3, m.v4);
        //terrain.AddQuadColor(cell.Color);
        terrain.AddTriangle(centerR, m.v4, m.v5);
        //terrain.AddTriangleColor(cell.Color);

        //terrain.AddTriangleColor(color1);
        //terrain.AddQuadColor(color1);
        //terrain.AddQuadColor(color1);
        //terrain.AddTriangleColor(color1);

        //Vector3 types;
        //types.x = types.y = types.z = cell.TerrainTypeIndex;
        //terrain.AddTriangulateTerrainType(types);
        //terrain.AddQuadTerrainType(types);
        //terrain.AddQuadTerrainType(types);
        //terrain.AddTriangulateTerrainType(types);

        Vector3 indices;

        indices.x = indices.y = indices.z = cell.Index;
        terrain.AddTriangleCellData(indices, weights1);
        terrain.AddQuadCellData(indices, weights1);
        terrain.AddQuadCellData(indices, weights1);
        terrain.AddTriangleCellData(indices, weights1);

        if (!cell.IsUnderwater)
        {
            bool reversed = cell.IncomingRiver == direction;
            TriangulateRiverQuad(centerL, centerR, m.v2, m.v4, cell.RiverSurfaceY, 0.4f, reversed, indices);
            TriangulateRiverQuad(m.v2, m.v4, e.v2, e.v4, cell.RiverSurfaceY, 0.6f, reversed, indices);
        }
    }
Example #3
0
    private void AddParticles(Vector3 center, HexDirection direction, HexCell cell)
    {
        var x    = center.x;
        var y    = center.y;
        var z    = center.z;
        var curA = new Vector3(0, 0, 0);
        var curB = new Vector3(0, 0, 0);
        var step = new Vector3(0, 0, 0);
        var rows = HexMetrics.OUTER_RADIUS;
        var v1   = HexMetrics.GetFirstSolidCorner(direction);
        var v2   = HexMetrics.GetSecondSolidCorner(direction);

        for (var i = 0; i < HexMetrics.OUTER_RADIUS; i++)
        {
            //Draw outer trinagles
            switch (i)
            {
            case 0:
                curA = new Vector3(x, y, z);
                break;

            case 1:
                curA = new Vector3(x, y, z) + v1 * HexMetrics.PARTICLE_SIZE;
                break;

            default:
                curA = step + v1 * HexMetrics.PARTICLE_SIZE;
                break;
            }

            for (var o = 0; o < rows; o++)
            {
                var a = curA;
                var b = curA + v1 * HexMetrics.PARTICLE_SIZE;
                var c = curA + v2 * HexMetrics.PARTICLE_SIZE;

                AdjustHeight(a, b, c, ref cell);

                curA = curA + v2 * HexMetrics.PARTICLE_SIZE;
            }

            //Draw covers
            switch (i)
            {
            case 0:
                step = new Vector3(x, y, z);
                curA = step + v2 * HexMetrics.PARTICLE_SIZE;
                curB = step + v1 * HexMetrics.PARTICLE_SIZE;
                break;

            default:
                step = step + v1 * HexMetrics.PARTICLE_SIZE;
                curA = step + v2 * HexMetrics.PARTICLE_SIZE;
                curB = step + v1 * HexMetrics.PARTICLE_SIZE;
                break;
            }

            for (var j = 0; j < rows - 1; j++)
            {
                var a = curA;
                var b = curB;
                var c = curA + v1 * HexMetrics.PARTICLE_SIZE;

                AdjustHeight(a, b, c, ref cell);

                curA = curA + v2 * HexMetrics.PARTICLE_SIZE;
                curB = curB + v2 * HexMetrics.PARTICLE_SIZE;
            }

            rows--;
        }
    }
    public void TriangulateWaterShore(HexDirection dir, HexCell hexCell, HexCell neighbour, Vector3 center)
    {
        EdgeVertices edges1 = new EdgeVertices(center + HexMetrics.GetFirstWaterCorner(dir), center + HexMetrics.GetSecondWaterCorner(dir));

        Water.AddTriangle(center, edges1.v1, edges1.v2);
        Water.AddTriangle(center, edges1.v2, edges1.v3);
        Water.AddTriangle(center, edges1.v3, edges1.v4);
        Water.AddTriangle(center, edges1.v4, edges1.v5);

        Vector3 indices = new Vector3(hexCell.CellIndex, hexCell.CellIndex, hexCell.CellIndex);

        Water.AddTriangleCellData(indices, Weights1);
        Water.AddTriangleCellData(indices, Weights1);
        Water.AddTriangleCellData(indices, Weights1);
        Water.AddTriangleCellData(indices, Weights1);

        Vector3 center2 = neighbour.Position;

        center2.y = center.y;
        if (neighbour.ColumnIndex < hexCell.ColumnIndex - 1)
        {
            center2.x += HexMetrics.WrapSize * HexMetrics.InnerDiameter;
        }
        else if (neighbour.ColumnIndex > hexCell.ColumnIndex + 1)
        {
            center2.x -= HexMetrics.WrapSize * HexMetrics.InnerDiameter;
        }


        Vector3      bridge = HexMetrics.GetWaterBridge(dir);
        EdgeVertices edges2 = new EdgeVertices(center2 + HexMetrics.GetSecondSolidCorner(dir.Opposite()), center2 + HexMetrics.GetFirstSolidCorner(dir.Opposite()));

        if (hexCell.HasRiverThroughEdge(dir))
        {
            TriangulateEstuary(edges1, edges2, hexCell.IncomingRiverDirection == dir, indices);
        }
        else
        {
            WaterShore.AddQuad(edges1.v1, edges1.v2, edges2.v1, edges2.v2);
            WaterShore.AddQuad(edges1.v2, edges1.v3, edges2.v2, edges2.v3);
            WaterShore.AddQuad(edges1.v3, edges1.v4, edges2.v3, edges2.v4);
            WaterShore.AddQuad(edges1.v4, edges1.v5, edges2.v4, edges2.v5);

            WaterShore.AddQuadUV(0f, 0f, 0f, 1f);
            WaterShore.AddQuadUV(0f, 0f, 0f, 1f);
            WaterShore.AddQuadUV(0f, 0f, 0f, 1f);
            WaterShore.AddQuadUV(0f, 0f, 0f, 1f);

            WaterShore.AddQuadCellData(indices, Weights1, Weights2);
            WaterShore.AddQuadCellData(indices, Weights1, Weights2);
            WaterShore.AddQuadCellData(indices, Weights1, Weights2);
            WaterShore.AddQuadCellData(indices, Weights1, Weights2);



            HexCell nextNeighbour = hexCell.GetNeighbour(dir.Next());
            if (nextNeighbour != null)
            {
                Vector3 center3 = nextNeighbour.Position;
                if (nextNeighbour.ColumnIndex < hexCell.ColumnIndex - 1)
                {
                    center3.x += HexMetrics.WrapSize * HexMetrics.InnerDiameter;
                }
                else if (nextNeighbour.ColumnIndex > hexCell.ColumnIndex + 1)
                {
                    center3.x -= HexMetrics.WrapSize * HexMetrics.InnerDiameter;
                }

                Vector3 v3 = center3 + (nextNeighbour.IsUnderwater ? HexMetrics.GetFirstWaterCorner(dir.Previous()) : HexMetrics.GetFirstSolidCorner(dir.Previous()));
                v3.y = center.y;


                WaterShore.AddTriangle(edges1.v5, edges2.v5, v3);
                WaterShore.AddTriangleUV(new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, 0f));
                WaterShore.AddTriangleCellData(indices, Weights1, Weights2, Weights3);
            }
        }
    }
Example #5
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 #6
0
    private void triangulateWaterShore(
        HexDirection direction, HexCell cell, HexCell neighbor, Vector3 center)
    {
        EdgeVertices e1 = new EdgeVertices(
            center + HexMetrics.GetFirstWaterCorner(direction),
            center + HexMetrics.GetSecondWaterCorner(direction));

        water.AddTriangle(center, e1.v1, e1.v2);
        water.AddTriangle(center, e1.v2, e1.v3);
        water.AddTriangle(center, e1.v3, e1.v4);
        water.AddTriangle(center, e1.v4, e1.v5);
        Vector3 indices;

        indices.x = indices.z = cell.Index;
        indices.y = neighbor.Index;
        water.AddTriangleCellData(indices, weights1);
        water.AddTriangleCellData(indices, weights1);
        water.AddTriangleCellData(indices, weights1);
        water.AddTriangleCellData(indices, weights1);

        Vector3 center2 = neighbor.Position;

        center2.y = center.y;
        EdgeVertices e2 = new EdgeVertices(
            center2 + HexMetrics.GetSecondSolidCorner(direction.Opposite()),
            center2 + HexMetrics.GetFirstSolidCorner(direction.Opposite()));

        if (cell.HasRiverThroughEdge(direction))
        {
            triangulateEstuary(e1, e2, cell.IncomingRiver == direction, indices);
        }
        else
        {
            waterShore.AddQuad(e1.v1, e1.v2, e2.v1, e2.v2);
            waterShore.AddQuad(e1.v2, e1.v3, e2.v2, e2.v3);
            waterShore.AddQuad(e1.v3, e1.v4, e2.v3, e2.v4);
            waterShore.AddQuad(e1.v4, e1.v5, e2.v4, e2.v5);
            waterShore.AddQuadUV(0f, 0f, 0f, 1f);
            waterShore.AddQuadUV(0f, 0f, 0f, 1f);
            waterShore.AddQuadUV(0f, 0f, 0f, 1f);
            waterShore.AddQuadUV(0f, 0f, 0f, 1f);
            waterShore.AddQuadCellData(indices, weights1, weights2);
            waterShore.AddQuadCellData(indices, weights1, weights2);
            waterShore.AddQuadCellData(indices, weights1, weights2);
            waterShore.AddQuadCellData(indices, weights1, weights2);
        }

        HexCell nextNeighbor = cell.GetNeighbor(direction.Next());

        if (nextNeighbor != null)
        {
            Vector3 v3 = nextNeighbor.Position + (nextNeighbor.IsUnderwater ?
                                                  HexMetrics.GetFirstWaterCorner(direction.Previous()) :
                                                  HexMetrics.GetFirstSolidCorner(direction.Previous()));
            v3.y = center.y;
            waterShore.AddTriangle(e1.v5, e2.v5, v3);
            waterShore.AddTriangleUV(
                new Vector2(0f, 0f),
                new Vector2(0f, 1f),
                new Vector2(0f, nextNeighbor.IsUnderwater ? 0f : 1f));
            indices.z = nextNeighbor.Index;
            waterShore.AddTriangleCellData(
                indices, weights1, weights2, weights3);
        }
    }
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
    private void TriangulateRoadAdjacentToRiver(
        HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e
        )
    {
        bool    hasRoadThroughEdge = cell.HasRoadThroughEdge(direction);
        bool    previousHasRiver   = cell.HasRiverThroughEdge(direction.Previous());
        bool    nextHasRiver       = cell.HasRiverThroughEdge(direction.Next());
        Vector2 interpolators      = GetRoadInterpolators(direction, cell);
        Vector3 roadCenter         = center;

        // Push the road center in the opposite direction of the river. This is
        // so that the road does not overlap with the river's begin or end.
        if (cell.HasRiverBeginOrEnd)
        {
            // Displace the center 1/3 of the distance to the edge middle point of the opposite direction.
            roadCenter += HexMetrics.GetSolidEdgeMiddle(cell.RiverBeginOrEndDirection.Opposite()) * (1f / 3f);

            // River crosses through the cell.
        }
        else if (cell.IncomingRiver == cell.OutgoingRiver.Opposite())
        {
            Vector3 corner;
            if (previousHasRiver)
            {
                if (
                    !hasRoadThroughEdge &&
                    !cell.HasRoadThroughEdge(direction.Next())
                    )
                {
                    return;
                }
                corner = HexMetrics.GetSecondSolidCorner(direction);
            }
            else
            {
                if (!hasRoadThroughEdge &&
                    !cell.HasRoadThroughEdge(direction.Previous()))
                {
                    return;
                }

                corner = HexMetrics.GetFirstSolidCorner(direction);
            }
            roadCenter += corner * 0.5f;
            center     += corner * 0.25f;
            // Zig Zag cases
            // Move the road center by using one of the corners of the incoming river direction.
            // Push the road center away from that corner.
        }
        else if (cell.IncomingRiver == cell.OutgoingRiver.Previous())
        {
            roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiver) * 0.2f;
        }
        else if (cell.IncomingRiver == cell.OutgoingRiver.Next())
        {
            roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiver) * 0.2f;

            // Inside of Curved Rivers
            // River on both sides of the current direction, that means there is a curved river. In
            // this case pull the Road towards the current cell edge, shortening the road.
        }
        else if (previousHasRiver && nextHasRiver)
        {
            // Prune isolated road parts, that is, do not render a road through that edge.
            if (!hasRoadThroughEdge)
            {
                return;
            }

            Vector3 offset = HexMetrics.GetSolidEdgeMiddle(direction) * HexMetrics.innerToOuter;
            roadCenter += offset * 0.7f;
            center     += offset * 0.5f;
            // Outside of a curving river
            // There are three cell parts on the outside, we have to
            // find the middle direction.
        }
        else
        {
            HexDirection middle;
            if (previousHasRiver)
            {
                middle = direction.Next();
            }
            else if (nextHasRiver)
            {
                middle = direction.Previous();
            }
            else
            {
                middle = direction;
            }
            // Prune this side of the river if there is no road that continues through
            // this direction, the previous or the next one.
            if (!cell.HasRoadThroughEdge(middle) &&
                !cell.HasRoadThroughEdge(middle.Previous()) &&
                !cell.HasRoadThroughEdge(middle.Next()))
            {
                return;
            }
            roadCenter += HexMetrics.GetSolidEdgeMiddle(middle) * 0.25f;
        }

        Vector3 mL = Vector3.Lerp(roadCenter, e.v1, interpolators.x);
        Vector3 mR = Vector3.Lerp(roadCenter, e.v5, interpolators.y);

        TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge);
        if (previousHasRiver)
        {
            TriangulateRoadEdge(roadCenter, center, mL);
        }
        if (nextHasRiver)
        {
            TriangulateRoadEdge(roadCenter, mR, center);
        }
    }
Example #9
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
                );
        }
    }
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
    void BoundaryEdge(HexDirection d, HexCell cell)
    {
        HexCell neighbor = cell.GetNeighbor(d);

        if (neighbor != null)
        {
            return;
        }                                 //Only check boundaries

        HexCell neighbor2 = cell.GetNeighbor(d.Next());
        HexCell neighbor3 = cell.GetNeighbor(d.Previous());
        Vector3 center = cell.transform.localPosition;
        Vector3 center2, v1, v2, v3, v4, tempV1;


        //Generate basic hex edge on any boundary

        v1 = center + HexMetrics.GetSecondSolidCorner(d, cell);
        v2 = center + HexMetrics.GetFirstSolidCorner(d, cell);

        tempV1 = ((cell.Height) * Vector3.up * HexMetrics.heightStep);
        v3     = (v1 - tempV1);
        v4     = (v2 - tempV1);

        AddTriangle(center + (((HexMetrics.GetFirstSolidCorner(d, cell)) + HexMetrics.GetSecondSolidCorner(d.Opposite(), cell)) / 2), (v2), (v1));
        AddTriangleColor(cell.color);

        AddQuad(v2, v1, v4, v3);
        AddQuadColor(cell.color, cell.color);

        if (neighbor2 == null)
        {
        }
        else if (!neighbor2.Checked[(int)d]) //Check right neighbor, add boundary edge if there isn't one
        {
            center2 = neighbor2.transform.position;

            v1 = center + HexMetrics.GetSecondSolidCorner(d, cell);
            v2 = center2 + HexMetrics.GetFirstSolidCorner(d.Previous(), neighbor2);

            tempV1 = cell.Height * Vector3.up * HexMetrics.heightStep;
            v3     = v1 - tempV1;

            tempV1 = neighbor2.Height * Vector3.up * HexMetrics.heightStep;
            v4     = v2 - tempV1;

            AddQuad(v1, v2, v3, v4);
            AddQuadColor(neighbor2.color, cell.color);

            neighbor2.Checked[(int)d] = true;
        }
        if (neighbor3 == null)
        {
        }
        else if (!neighbor3.Checked[(int)d]) //Check left neighbor, add boundary edge if there isn't one
        {
            center2 = neighbor3.transform.position;

            v1 = center2 + HexMetrics.GetSecondSolidCorner(d.Next(), neighbor3);
            v2 = center + HexMetrics.GetFirstSolidCorner(d, cell);

            tempV1 = neighbor3.Height * Vector3.up * HexMetrics.heightStep;
            v3     = v1 - tempV1;

            tempV1 = cell.Height * Vector3.up * HexMetrics.heightStep;
            v4     = v2 - tempV1;

            AddQuad(v1, v2, v3, v4);
            AddQuadColor(neighbor3.color, cell.color);

            neighbor3.Checked[(int)d] = true;
        }
    }
Example #12
0
    void TriangulateRoadAdjacentToRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e)
    {
        bool    hasRoadThroughEdge = cell.HasRoadThroughEdge(direction);
        bool    previousHasRiver   = cell.HasRiverThroughEdge(direction.Previous());
        bool    nextHasRiver       = cell.HasRiverThroughEdge(direction.Next());
        Vector2 interpolators      = GetRoadInterpolators(direction, cell);
        Vector3 roadCenter         = center;

        // Push road center away from river
        if (cell.HasRiverBeginOrEnd)
        {
            roadCenter += HexMetrics.GetSolidEdgeMiddle(cell.RiverBeginOrEndDirection.Opposite()) * (1f / 3f);
        }

        // Disconnect road on opposite side of river
        else if (cell.IncomingRiver == cell.OutgoingRiver.Opposite())
        {
            Vector3 corner;
            if (previousHasRiver)
            {
                if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Next()))
                {
                    return;
                }
                corner = HexMetrics.GetSecondSolidCorner(direction);
            }
            else
            {
                if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Previous()))
                {
                    return;
                }
                corner = HexMetrics.GetFirstSolidCorner(direction);
            }
            roadCenter += corner * 0.5f;
            center     += corner * 0.25f;
        }
        else if (cell.IncomingRiver == cell.OutgoingRiver.Previous())
        {
            roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiver) * 0.2f;
        }
        else if (cell.IncomingRiver == cell.OutgoingRiver.Next())
        {
            roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiver) * 0.2f;
        }
        else if (previousHasRiver && nextHasRiver)
        {
            if (!hasRoadThroughEdge)
            {
                return;
            }
            Vector3 offset = HexMetrics.GetSolidEdgeMiddle(direction) * HexMetrics.innerToOuter;
            roadCenter += offset * 0.7f;
            center     += offset * 0.5f;
        }
        else
        {
            HexDirection middle;
            if (previousHasRiver)
            {
                middle = direction.Next();
            }
            else if (nextHasRiver)
            {
                middle = direction.Previous();
            }
            else
            {
                middle = direction;
            }
            if (!cell.HasRoadThroughEdge(middle) &&
                !cell.HasRoadThroughEdge(middle.Previous()) &&
                !cell.HasRoadThroughEdge(middle.Next()))
            {
                return;
            }
            roadCenter += HexMetrics.GetSolidEdgeMiddle(middle) * 0.25f;
        }
        Vector3 mL = Vector3.Lerp(roadCenter, e.v1, interpolators.x);
        Vector3 mR = Vector3.Lerp(roadCenter, e.v5, interpolators.y);

        TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge);

        // Close gaps in road created by river
        if (previousHasRiver)
        {
            TriangulateRoadEdge(roadCenter, center, mL);
        }
        if (nextHasRiver)
        {
            TriangulateRoadEdge(roadCenter, mR, center);
        }
    }
Example #13
0
    /// <summary>
    /// 河流穿过cell
    /// </summary>
    /// <param name="direction"></param>
    /// <param name="cell"></param>
    /// <param name="center"></param>
    /// <param name="e"></param>
    void TriangulateWithRiver(
        HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e
        )
    {
        Vector3 centerL, centerR;

        // 河流对穿cell
        if (cell.HasRiverThroughEdge(direction.Opposite()))
        {
            // 画出中间沟槽
            centerL = center +
                      HexMetrics.GetFirstSolidCorner(direction.Previous()) * 0.25f;
            centerR = center +
                      HexMetrics.GetSecondSolidCorner(direction.Next()) * 0.25f;
        }         // 河流一步回转,下位穿出
        else if (cell.HasRiverThroughEdge(direction.Next()))
        {
            centerL = center;
            centerR = Vector3.Lerp(center, e.v5, 2f / 3f);
        }         // 河流一步回转,上位穿出
        else if (cell.HasRiverThroughEdge(direction.Previous()))
        {
            centerL = Vector3.Lerp(center, e.v1, 2f / 3f);
            centerR = center;
        }         // 河流二步回转,下位穿出
        else if (cell.HasRiverThroughEdge(direction.Next2()))
        {
            centerL = center;
            centerR = center +
                      HexMetrics.GetSolidEdgeMiddle(direction.Next()) *
                      (0.5f * HexMetrics.innerToOuter);
        }
        else
        {
            centerL = center +
                      HexMetrics.GetSolidEdgeMiddle(direction.Previous()) *
                      (0.5f * HexMetrics.innerToOuter);
            centerR = center;
        }
        center = Vector3.Lerp(centerL, centerR, 0.5f);

        EdgeVertices m = new EdgeVertices(
            Vector3.Lerp(centerL, e.v1, 0.5f),
            Vector3.Lerp(centerR, e.v5, 0.5f),
            1f / 6f
            );

        m.v3.y = center.y = e.v3.y;

        TriangulateEdgeStrip(m, cell.Color, e, cell.Color);

        terrain.AddTriangle(centerL, m.v1, m.v2);
        terrain.AddTriangleColor(cell.Color);
        terrain.AddQuad(centerL, center, m.v2, m.v3);
        terrain.AddQuadColor(cell.Color);
        terrain.AddQuad(center, centerR, m.v3, m.v4);
        terrain.AddQuadColor(cell.Color);
        terrain.AddTriangle(centerR, m.v4, m.v5);
        terrain.AddTriangleColor(cell.Color);

        bool reversed = cell.IncomingRiver == direction;

        TriangulateRiverQuad(
            centerL, centerR, m.v2, m.v4, cell.RiverSurfaceY, 0.4f, reversed
            );
        TriangulateRiverQuad(
            m.v2, m.v4, e.v2, e.v4, cell.RiverSurfaceY, 0.6f, reversed
            );
    }
Example #14
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 - center * 0.5f);
            }
            center += corner * 0.25f;
        }
        else if (cell.IncomingRiver == cell.OutgoingRiver.Previous())
        {
            roadCenter -= HexMetrics.GetSecondCorner(cell.IncomingRiver) * 0.2f;
        }
        else if (cell.IncomingRiver == cell.OutgoingRiver.Next())
        {
            roadCenter -= HexMetrics.GetFirstCorner(cell.IncomingRiver) * 0.2f;
        }
        else if (previousHasRiver && nextHasRiver)
        {
            if (!hasRoadThroughEdge)
            {
                return;
            }
            Vector3 offset = HexMetrics.GetSolidEdgeMiddle(direction) * HexMetrics.innerToOuter;
            roadCenter += offset * 0.7f;
            center     += offset * 0.5f;
        }
        else
        {
            HexDirection middle;
            if (previousHasRiver)
            {
                middle = direction.Next();
            }
            else if (nextHasRiver)
            {
                middle = direction.Previous();
            }
            else
            {
                middle = direction;
            }

            if (
                !cell.HasRoadThroughEdge(middle) &&
                !cell.HasRoadThroughEdge(middle.Previous()) &&
                !cell.HasRoadThroughEdge(middle.Next())
                )
            {
                return;
            }

            Vector3 offset = HexMetrics.GetSolidEdgeMiddle(middle);
            //roadCenter += HexMetrics.GetSolidEdgeMiddle(middle) * 0.25f;
            roadCenter += offset * 0.25f;
            //弯曲河流加入桥梁
            if (
                direction == middle &&
                cell.HasRoadThroughEdge(direction.Opposite())
                )
            {
                features.AddBridge(roadCenter, center - offset * (HexMetrics.innerToOuter * 0.7f));
            }
        }

        Vector3 mL = Vector3.Lerp(roadCenter, e.v1, interpolators.x);
        Vector3 mR = Vector3.Lerp(roadCenter, e.v5, interpolators.y);

        TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge, cell.Index);

        if (previousHasRiver)
        {
            TriangulateRoadEdge(roadCenter, center, mL, cell.Index);
        }
        if (nextHasRiver)
        {
            TriangulateRoadEdge(roadCenter, mR, center, cell.Index);
        }
    }
Example #15
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 #16
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 #17
0
    private void TriangulateWithRiver(
        HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e)
    {
        Vector3 centerL, centerR;

        // Two cases:
        // If the cell has a river going through the opposite direction as well as the direction
        // that we are working with, the cell holds a straight river.
        if (cell.HasRiverThroughEdge(direction.Opposite()))
        {
            // Stretch the center into a line. Move 25% from the center to the first corner of the previous
            // direction, and 25% from the center to the second corner of the second direction.
            // One simple way of visualizing this is having a top-down view of the HexMesh and imagining
            // a triangulation in the eastern direction.
            centerL = center + HexMetrics.GetFirstSolidCorner(direction.Previous()) * 0.25f;
            centerR = center + HexMetrics.GetSecondSolidCorner(direction.Next()) * 0.25f;

            // Otherwise, the river does not flow in a straight line, check special cases:
            // Detect sharp turns by checking whether the cell has a rive going through the next
            // or previous cell part.
            // When there is a sharp turn, align the center line with the edge between this and the adjacent part.
        }
        else if (cell.HasRiverThroughEdge(direction.Next()))
        {
            centerL = center;
            centerR = Vector3.Lerp(center, e.v5, 2f / 3f /* Increased center line width from 1/2 to 2/3 */);
        }
        else if (cell.HasRiverThroughEdge(direction.Previous()))
        {
            centerL = Vector3.Lerp(center, e.v1, 2f / 3f /* Increased center line width from 1/2 to 2/3 */);
            centerR = center;

            // 2 step rotations, these produce gently curving rivers.
            // A river is going through two directions after this one.
            // Expand the center towards the center of the next direction's edge.
        }
        else if (cell.HasRiverThroughEdge(direction.Next2()))
        {
            centerL = center;
            // Note that the edge middle point is closer that the vertex itself (it's within the inner radius)
            // which is why extending the center towards that edge will end up with a pinched section.
            // We extend the center edge towards the middle edge times innerToOuter radius to keep
            // the channel width constant.
            centerR = center + HexMetrics.GetSolidEdgeMiddle(direction.Next())
                      * (0.5f * HexMetrics.innerToOuter);
            // 2 step rotation, a river is going through two directions before this one.
        }
        else
        {
            centerL = center + HexMetrics.GetSolidEdgeMiddle(direction.Previous())
                      * (0.5f * HexMetrics.innerToOuter);
            centerR = center;
        }

        // Determine the final center by averaging the Left and Right centers
        center = Vector3.Lerp(centerL, centerR, 0.5f);

        // We lerp the second and fourth vertices using 1/6 instead of the usual 1/4 as the
        // length from the edges is 1/8 instead of 1/4. This is because the channel has a
        // the same width along the river, so the relative edge length of the outer edges
        // will be 1/6 relative to the edge's middle length. (1/8 of 3/4)
        EdgeVertices m = new EdgeVertices(
            Vector3.Lerp(centerL, e.v1, 0.5f),
            Vector3.Lerp(centerR, e.v5, 0.5f),
            1f / 6f);

        m.v3.y = center.y = e.v3.y;
        TriangulateEdgeStrip(m, cell.Color, e, cell.Color);

        // Add the triangles and quads that reached the center.
        terrain.AddTriangle(centerL, m.v1, m.v2);
        terrain.AddTriangleColor(cell.Color);

        terrain.AddQuad(centerL, center, m.v2, m.v3);
        terrain.AddQuadColor(cell.Color);
        terrain.AddQuad(center, centerR, m.v3, m.v4);
        terrain.AddQuadColor(cell.Color);

        terrain.AddTriangle(centerR, m.v4, m.v5);
        terrain.AddTriangleColor(cell.Color);

        if (!cell.IsUnderwater)
        {
            bool reversed = cell.IncomingRiver == direction;
            TriangulateRiverQuad(centerL, centerR, m.v2, m.v4, cell.RiverSurfaceY, 0.4f, reversed);
            TriangulateRiverQuad(m.v2, m.v4, e.v2, e.v4, cell.RiverSurfaceY, 0.6f, reversed);
        }
    }