public void TriangulateEstuary(EdgeVertices edges1, EdgeVertices edges2, bool incomingRiver, Vector3 indices)
    {
        WaterShore.AddTriangle(edges2.v1, edges1.v2, edges1.v1);
        WaterShore.AddTriangle(edges2.v5, edges1.v5, edges1.v4);
        WaterShore.AddTriangleUV(new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(0f, 0f));
        WaterShore.AddTriangleUV(new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(0f, 0f));
        WaterShore.AddTriangleCellData(indices, Weights2, Weights1, Weights1);
        WaterShore.AddTriangleCellData(indices, Weights2, Weights1, Weights1);

        Estuaries.AddQuad(edges2.v1, edges1.v2, edges2.v2, edges1.v3);
        Estuaries.AddTriangle(edges1.v3, edges2.v2, edges2.v4);
        Estuaries.AddQuad(edges1.v3, edges1.v4, edges2.v4, edges2.v5);

        Estuaries.AddQuadUV(new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, 0f));
        Estuaries.AddTriangleUV(new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, 1f));
        Estuaries.AddQuadUV(0f, 0f, 0f, 1f);

        Estuaries.AddQuadCellData(indices, Weights2, Weights1, Weights2, Weights1);
        Estuaries.AddTriangleCellData(indices, Weights1, Weights2, Weights2);
        Estuaries.AddQuadCellData(indices, Weights1, Weights2);

        if (incomingRiver)
        {
            Estuaries.AddQuadUV2(new Vector2(1.5f, 1f), new Vector2(0.7f, 1.15f), new Vector2(1f, 0.8f), new Vector2(0.5f, 1.1f));
            Estuaries.AddTriangleUV2(new Vector2(0.5f, 1.1f), new Vector2(1f, 0.8f), new Vector2(0f, 0.8f));
            Estuaries.AddQuadUV2(new Vector2(0.5f, 1.1f), new Vector2(0.3f, 1.15f), new Vector2(0f, 0.8f), new Vector2(-0.5f, 1f));
        }
        else
        {
            Estuaries.AddQuadUV2(new Vector2(-0.5f, -0.2f), new Vector2(0.3f, -0.35f), new Vector2(0f, 0f), new Vector2(0.5f, -0.3f));
            Estuaries.AddTriangleUV2(new Vector2(0.5f, -0.3f), new Vector2(0f, 0f), new Vector2(1f, 0f));
            Estuaries.AddQuadUV2(new Vector2(0.5f, -0.3f), new Vector2(0.7f, -0.35f), new Vector2(1f, 0f), new Vector2(1.5f, -0.2f));
        }
    }
 public void TriangulateRoadSegment(Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4, Vector3 v5, Vector3 v6, Color w1, Color w2, Vector3 indices)
 {
     Roads.AddQuad(v1, v2, v4, v5);
     Roads.AddQuad(v2, v3, v5, v6);
     Roads.AddQuadUV(0, 1, 0, 0);
     Roads.AddQuadUV(1, 0, 0, 0);
     Roads.AddQuadCellData(indices, w1, w2);
     Roads.AddQuadCellData(indices, w1, w2);
 }
Exemple #3
0
 void TriangulateRoadSegment(Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4, Vector3 v5, Vector3 v6, Color w1, Color w2, Vector3 indices)
 {
     roads.AddQuad(v1, v2, v4, v5);
     roads.AddQuad(v2, v3, v5, v6);
     roads.AddQuadUV(0f, 1f, 0f, 0f);
     roads.AddQuadUV(1f, 0f, 0f, 0f);
     roads.AddQuadCellData(indices, w1, w2);
     roads.AddQuadCellData(indices, w1, w2);
 }
Exemple #4
0
 protected static void TriangulateQuad(HexMesh mesh, EdgeVertices e1, EdgeVertices e2, Color c1, Color c2)
 {
     mesh.AddQuad(e1.v1, e1.v2, e2.v1, e2.v2);
     mesh.AddQuadColor(c1, c1, c2, c2);
     mesh.AddQuad(e1.v2, e1.v3, e2.v2, e2.v3);
     mesh.AddQuadColor(c1, c1, c2, c2);
     mesh.AddQuad(e1.v3, e1.v4, e2.v3, e2.v4);
     mesh.AddQuadColor(c1, c1, c2, c2);
     mesh.AddQuad(e1.v4, e1.v5, e2.v4, e2.v5);
     mesh.AddQuadColor(c1, c1, c2, c2);
 }
Exemple #5
0
    void TriangulatePointTerraces(Vector3 begin, HexCell beginCell, Vector3 left,
                                  HexCell leftCell, Vector3 right, HexCell rightCell)
    {
        Vector3 v3 = Hex.TerraceLerp(begin, left, 1);
        Vector3 v4 = Hex.TerraceLerp(begin, right, 1);
        Color   w3 = Hex.TerraceLerp(weights1, weights2, 1);
        Color   w4 = Hex.TerraceLerp(weights1, weights3, 1);
        Vector3 indices;

        indices.x = beginCell.Index;
        indices.y = leftCell.Index;
        indices.z = rightCell.Index;

        terrain.AddTriangle(begin, v3, v4);
        terrain.AddTriangleCellData(indices, weights1, w3, w4);

        for (int i = 2; i < Hex.terracesSteps; i++)
        {
            Vector3 v1 = v3;
            Vector3 v2 = v4;
            Color   w1 = w3;
            Color   w2 = w4;
            v3 = Hex.TerraceLerp(begin, left, i);
            v4 = Hex.TerraceLerp(begin, right, i);
            w3 = Hex.TerraceLerp(weights1, weights2, i);
            w4 = Hex.TerraceLerp(weights1, weights3, i);
            terrain.AddQuad(v1, v2, v3, v4);
            terrain.AddQuadCellData(indices, w1, w2, w3, w4);
        }

        terrain.AddQuad(v3, v4, left, right);
        terrain.AddQuadCellData(indices, w3, w4, weights2, weights3);
    }
Exemple #6
0
    void TriangulateCornerTerraces(Vector3 begin, HexCell beginCell, Vector3 left, HexCell leftCell, Vector3 right, HexCell rightCell)
    {
        Vector3 v3 = HexMetrics.TerraceLerp(begin, left, 1);
        Vector3 v4 = HexMetrics.TerraceLerp(begin, right, 1);
        Color   c3 = HexMetrics.TerraceLerp(beginCell.Color, leftCell.Color, 1);
        Color   c4 = HexMetrics.TerraceLerp(beginCell.Color, rightCell.Color, 1);

        terrain.AddTriangle(begin, v3, v4);
        terrain.AddTriangleColor(beginCell.Color, c3, c4);

        for (int i = 2; i < HexMetrics.terraceSteps; i++)
        {
            Vector3 v1 = v3;
            Vector3 v2 = v4;
            Color   c1 = c3;
            Color   c2 = c4;
            v3 = HexMetrics.TerraceLerp(begin, left, i);
            v4 = HexMetrics.TerraceLerp(begin, right, i);
            c3 = HexMetrics.TerraceLerp(beginCell.Color, leftCell.Color, i);
            c4 = HexMetrics.TerraceLerp(beginCell.Color, rightCell.Color, i);
            terrain.AddQuad(v1, v2, v3, v4);
            terrain.AddQuadColor(c1, c2, c3, c4);
        }

        terrain.AddQuad(v3, v4, left, right);
        terrain.AddQuadColor(c3, c4, leftCell.Color, rightCell.Color);
    }
    void TriangulateEdgeStrip(EdgeVertices e1,
                              Color w1,
                              float index1,
                              EdgeVertices e2,
                              Color w2,
                              float index2,
                              bool hasRoad = false)
    {
        terrain.AddQuad(e1.v1, e1.v2, e2.v1, e2.v2);
        terrain.AddQuad(e1.v2, e1.v3, e2.v2, e2.v3);
        terrain.AddQuad(e1.v3, e1.v4, e2.v3, e2.v4);
        terrain.AddQuad(e1.v4, e1.v5, e2.v4, e2.v5);

        Vector3 indices;

        indices.x = indices.z = index1;
        indices.y = index2;
        terrain.AddQuadCellData(indices, w1, w2);
        terrain.AddQuadCellData(indices, w1, w2);
        terrain.AddQuadCellData(indices, w1, w2);
        terrain.AddQuadCellData(indices, w1, w2);

        if (hasRoad)
        {
            TriangulateRoadSegment(e1.v2, e1.v3, e1.v4, e2.v2, e2.v3, e2.v4, w1, w2, indices);
        }
    }
    public void TriangulateWithRiver(HexDirection dir, HexCell cell, Vector3 center, EdgeVertices edges)
    {
        Vector3 centerL;
        Vector3 centerR;

        float centerLinePinch = 2.0f / 3.0f;

        if (cell.HasRiverThroughEdge(dir.Opposite()))
        {
            centerL = center + HexMetrics.GetFirstSolidCorner(dir.Previous()) * HexMetrics.SubdivideFraction;
            centerR = center + HexMetrics.GetSecondSolidCorner(dir.Next()) * HexMetrics.SubdivideFraction;
            center  = (centerL + centerR) / 2.0f;
        }
        else if (cell.HasRiverThroughEdge(dir.Next()))
        {
            centerL = center;
            centerR = Vector3.Lerp(center, edges.v5, centerLinePinch);
        }
        else if (cell.HasRiverThroughEdge(dir.Previous()))
        {
            centerL = Vector3.Lerp(center, edges.v1, centerLinePinch);
            centerR = center;
        }
        else if (cell.HasRiverThroughEdge(dir.Next2()))
        {
            centerL = center;
            centerR = center + HexMetrics.GetSolidEdgeMiddle(dir.Next()) * (0.5f * HexMetrics.InnerToOuter);
        }
        else
        {
            centerL = center + HexMetrics.GetSolidEdgeMiddle(dir.Previous()) * (0.5f * HexMetrics.InnerToOuter);
            centerR = center;
        }

        EdgeVertices modifiedEdges = new EdgeVertices(Vector3.Lerp(centerL, edges.v1, 0.5f), Vector3.Lerp(centerR, edges.v5, 0.5f));

        modifiedEdges.v3.y = center.y = edges.v3.y;

        TriangulateEdgeStrip(modifiedEdges, Weights1, cell.TerrainTypeIndex, edges, Weights1, cell.CellIndex);

        Terrain.AddTriangle(centerL, modifiedEdges.v1, modifiedEdges.v2);
        Terrain.AddQuad(centerL, center, modifiedEdges.v2, modifiedEdges.v3);
        Terrain.AddQuad(center, centerR, modifiedEdges.v3, modifiedEdges.v4);
        Terrain.AddTriangle(centerR, modifiedEdges.v4, modifiedEdges.v5);

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

        Terrain.AddTriangleCellData(indices, Weights1);
        Terrain.AddQuadCellData(indices, Weights1);
        Terrain.AddQuadCellData(indices, Weights1);
        Terrain.AddTriangleCellData(indices, Weights1);

        if (!cell.IsUnderwater)
        {
            bool reverse = cell.IncomingRiverDirection == dir;

            TriangulateRiverQuad(centerL, centerR, modifiedEdges.v2, modifiedEdges.v4, cell.RiverSurfaceY, 0.4f, reverse, indices);
            TriangulateRiverQuad(modifiedEdges.v2, modifiedEdges.v4, edges.v2, edges.v4, cell.RiverSurfaceY, 0.6f, reverse, indices);
        }
    }
Exemple #9
0
    /* Creates a quad stretching from a cell's solid boundary to its true edge*/
    void TriangulateEdge(HexDirection direction, HexCell cell)
    {
        Vector3      center = cell.transform.localPosition;
        EdgeVertices e1     = new EdgeVertices(
            center + HexMetrics.GetFirstSolidCorner(direction),
            center + HexMetrics.GetSecondSolidCorner(direction)
            );
        EdgeVertices e2 = new EdgeVertices(
            center + HexMetrics.GetFirstCorner(direction),
            center + HexMetrics.GetSecondCorner(direction)
            );

        edgeMesh.AddQuad(e1, e2);
    }
Exemple #10
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);
        }
    }
Exemple #11
0
    public override void Triangulate(HexMesh mesh)
    {
        Vector3 v1 = beginCorner;
        Vector3 v2 = beginCorner;
        Color   c1 = beginCell.Color;
        Color   c2 = beginCell.Color;

        for (int step = 1; step < HexMetrics.terraceSteps + 1; ++step)
        {
            Vector3 v3 = HexMetrics.TerraceLerp(beginCorner, leftCorner, step);
            Vector3 v4 = HexMetrics.TerraceLerp(beginCorner, rightCorner, step);

            Color c3 = HexMetrics.ColorLerp(beginCell.Color, leftCell.Color, step);
            Color c4 = HexMetrics.ColorLerp(beginCell.Color, rightCell.Color, step);

            if (step == 1)
            {
                mesh.AddTriangle(v1, v3, v4);
                mesh.AddTriangleColor(c1, c3, c4);
            }
            else
            {
                mesh.AddQuad(v1, v2, v3, v4);
                mesh.AddQuadColor(c1, c2, c3, c4);
            }
            v1 = v3;
            v2 = v4;
            c1 = c3;
            c2 = c4;
        }
    }
    public void TriangulateOpenWater(HexDirection dir, HexCell cell, HexCell neighbour, Vector3 center)
    {
        Vector3 c1 = center + HexMetrics.GetFirstWaterCorner(dir);
        Vector3 c2 = center + HexMetrics.GetSecondWaterCorner(dir);

        Water.AddTriangle(center, c1, c2);

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

        Water.AddTriangleCellData(indices, Weights1);

        if (dir <= HexDirection.SE && neighbour != null)
        {
            Vector3 bridge = HexMetrics.GetWaterBridge(dir);
            Vector3 e1     = c1 + bridge;
            Vector3 e2     = c2 + bridge;

            Water.AddQuad(c1, c2, e1, e2);
            indices.y = neighbour.CellIndex;
            Water.AddQuadCellData(indices, Weights1, Weights2);

            if (dir <= HexDirection.E)
            {
                HexCell nextNeightbour = cell.GetNeighbour(dir.Next());
                if (nextNeightbour == null || !nextNeightbour.IsUnderwater)
                {
                    return;
                }
                Water.AddTriangle(c2, e2, c2 + HexMetrics.GetWaterBridge(dir.Next()));
                indices.z = nextNeightbour.CellIndex;
                Water.AddTriangleCellData(indices, Weights1, Weights2, Weights3);
            }
        }
    }
Exemple #13
0
    void TriangulateOpenWater(HexDirection direction, HexCell cell, HexCell neighbor, Vector3 center)
    {
        Vector3 c1 = center + HexMetrics.GetFirstWaterCorner(direction);
        Vector3 c2 = center + HexMetrics.GetSecondWaterCorner(direction);

        water.AddTriangle(center, c1, c2);
        Vector3 indices;

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

        if (direction <= HexDirection.SE && neighbor != null)
        {
            Vector3 bridge = HexMetrics.GetWaterBridge(direction);
            Vector3 e1     = c1 + bridge;
            Vector3 e2     = c2 + bridge;
            water.AddQuad(c1, c2, e1, e2);
            indices.y = neighbor.Index;
            water.AddQuadCellData(indices, weights1, weights2);

            if (direction <= HexDirection.E)
            {
                HexCell nextNeighbor = cell.GetNeighbor(direction.Next());
                if (nextNeighbor == null || !nextNeighbor.IsUnderWater)
                {
                    return;
                }
                water.AddTriangle(c2, e2, c2 + HexMetrics.GetWaterBridge(direction.Next()));
                indices.z = nextNeighbor.Index;
                water.AddTriangleCellData(indices, weights1, weights2, weights3);
            }
        }
    }
Exemple #14
0
    void TriangulateWallStrip(HexDirection d, HexCell cell)
    {
        HexDirection castDir = d.Opposite();
        HexCell      n       = cell.GetNeighbor(castDir);

        if (CheckCellValid(n))
        {
            //limit to prevent infinite loops if something goes wrong
            for (int i = 0; i < 10; i++)
            {
                HexCell n2 = n.GetNeighbor(castDir);
                if (CheckCellValid(n2))
                {
                    n = n2;
                }
                else
                {
                    break;
                }
            }
            //n is final cell
            Vector3 offset = new Vector3(0, wallHeight, 0);

            EdgeVertices e1 = new EdgeVertices(
                cell.transform.localPosition + HexMetrics.GetFirstSolidCorner(castDir),
                n.transform.localPosition + HexMetrics.GetSecondSolidCorner(d)
                );

            EdgeVertices e2 = new EdgeVertices(
                e1.v1 + offset,
                e1.v2 + offset
                );
            wallMesh.AddQuad(e1, e2);

            EdgeVertices e3 = new EdgeVertices(
                offset + cell.transform.localPosition + HexMetrics.GetFirstCorner(castDir),
                offset + n.transform.localPosition + HexMetrics.GetSecondCorner(d)
                );
            wallMesh.AddQuad(e2, e3);

            EdgeVertices e4 = new EdgeVertices(
                offset + cell.transform.localPosition + HexMetrics.GetFirstCorner(castDir.Previous()),
                offset + n.transform.localPosition + HexMetrics.GetSecondCorner(d.Next())
                );
            wallMesh.AddQuad(e3, e4);
        }
    }
Exemple #15
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.kInnerToOuter);
        }
        else
        {
            centerL = center + HexMetrics.GetSolidEdgeMiddle(direction.Previous()) * (0.5f * HexMetrics.kInnerToOuter);
            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, cell.RiverSurfaceY, 0.5f, HexMetrics.kRiverSolidUVStep, reversed);
            TriangulateRiverQuad(m.v2, m.v4, e.v2, e.v4, cell.RiverSurfaceY, cell.RiverSurfaceY, 0.5f + HexMetrics.kRiverSolidUVStep, HexMetrics.kRiverSolidUVStep, reversed);
        }
    }
Exemple #16
0
    /// <summary>
    /// 三角化角落阶梯,用于三角化三边分别是:平、阶、阶的角落
    /// </summary>
    /// <param name="begin"></param>
    /// <param name="beginCell">三角形阶梯所在六边形</param>
    /// <param name="left"></param>
    /// <param name="leftCell"></param>
    /// <param name="right"></param>
    /// <param name="rightCell"></param>
    void TriangulateCornerTerraces(Vector3 begin, HexCell beginCell, Vector3 left, HexCell leftCell, Vector3 right, HexCell rightCell)
    {
        Vector3 v3 = HexMetrics.TerraceLerp(begin, left, 1);
        Vector3 v4 = HexMetrics.TerraceLerp(begin, right, 1);
        Color   c3 = HexMetrics.TerraceLerp(weights1, weights2, 1);
        Color   c4 = HexMetrics.TerraceLerp(weights1, weights3, 1);

        Vector3 indices;

        indices.x = beginCell.Index;
        indices.y = leftCell.Index;
        indices.z = rightCell.Index;

        // 先生成第一个三角形
        terrain.AddTriangle(begin, v3, v4);                     // 顶点和三角索引
        terrain.AddTriangleCellData(indices, weights1, c3, c4); // 地形类型和splat颜色

        // 后面的阶梯生成四边形
        for (int i = 2; i <= HexMetrics.terraceSteps; i++)
        {
            Vector3 v1 = v3;
            Vector3 v2 = v4;
            Color   c1 = c3;
            Color   c2 = c4;

            v3 = HexMetrics.TerraceLerp(begin, left, i);
            v4 = HexMetrics.TerraceLerp(begin, right, i);
            c3 = HexMetrics.TerraceLerp(weights1, weights2, i);
            c4 = HexMetrics.TerraceLerp(weights1, weights3, i);
            terrain.AddQuad(v1, v2, v3, v4);
            terrain.AddQuadCellData(indices, c1, c2, c3, c4);
        }
    }
Exemple #17
0
 void TriangulateEdgeStrip(EdgeVertices e1, Color c1, EdgeVertices e2, Color c2)
 {
     terrain.AddQuad(e1.v1, e1.v2, e2.v1, e2.v2);
     terrain.AddQuadColor(c1, c2);
     terrain.AddQuad(e1.v2, e1.v3, e2.v2, e2.v3);
     terrain.AddQuadColor(c1, c2);
     terrain.AddQuad(e1.v3, e1.v4, e2.v3, e2.v4);
     terrain.AddQuadColor(c1, c2);
     terrain.AddQuad(e1.v4, e1.v5, e2.v4, e2.v5);
     terrain.AddQuadColor(c1, c2);
 }
Exemple #18
0
    /// <summary>
    /// 三角化河口
    /// </summary>
    /// <param name="e1">自身纯色区扇形边(弧)</param>
    /// <param name="e2">邻居纯色区扇形边(弧)</param>
    /// <param name="incomingRiver">是否是流入河</param>
    /// <param name="indices">临近六边形</param>
    void TriangulateEstuary(EdgeVertices e1, EdgeVertices e2, bool incomingRiver, Vector3 indices)
    {
        waterShore.AddTriangle(e2.v1, e1.v2, e1.v1);
        waterShore.AddTriangle(e2.v5, e1.v5, e1.v4);
        waterShore.AddTriangleUV(new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(0f, 0f));
        waterShore.AddTriangleUV(new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(0f, 0f));
        waterShore.AddTriangleCellData(indices, weights2, weights1, weights1);                      // 第一个顶点位于邻居六边形内所以用weights2,第二三个顶点位于自身六边形所以用weights1
        waterShore.AddTriangleCellData(indices, weights2, weights1, weights1);

        // 河口顶点 : e2:     v1----v5
        //            e1:      v2--v4
        //
        estuaries.AddQuad(e2.v1, e1.v2, e2.v2, e1.v3);
        estuaries.AddTriangle(e1.v3, e2.v2, e2.v4);
        estuaries.AddQuad(e1.v3, e1.v4, e2.v4, e2.v5);

        // 该UV的v用于判断离岸远近,u用于匹配瀑布水流消失插值(瀑布下方为1,扩散外围为0)
        estuaries.AddQuadUV(new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(1f, 1f), new Vector2(0f, 0f));
        estuaries.AddTriangleUV(new Vector2(0f, 0f), new Vector2(1f, 1f), new Vector2(1f, 1f));
        estuaries.AddQuadUV(new Vector2(0f, 0f), new Vector2(0f, 0f), new Vector2(1f, 1f), new Vector2(0f, 1f));

        // 六边形格子数据
        estuaries.AddQuadCellData(indices, weights2, weights1, weights2, weights1);
        estuaries.AddTriangleCellData(indices, weights1, weights2, weights2);
        estuaries.AddQuadCellData(indices, weights1, weights2);

        // 如果是流入河流的河口
        if (incomingRiver)
        {
            // uv2 用于匹配河水流动, v为河水流动方向
            // 由于是河口位于桥的下面,所以v坐标是0.8~1,
            // 由于水平面纯色区占比只有0.6,陆地水面交接处的桥是0.2+0.4,比陆地与陆地交接处的桥(0.2+0.2)大了50%,所以v坐标扩大50%,变成0.8~1.1
            estuaries.AddQuadUV2(new Vector2(1.5f, 1f), new Vector2(0.7f, 1.15f), new Vector2(1f, 0.8f), new Vector2(0.5f, 1.1f));
            estuaries.AddTriangleUV2(new Vector2(0.5f, 1.1f), new Vector2(1f, 0.8f), new Vector2(0f, 0.8f));
            estuaries.AddQuadUV2(new Vector2(0.5f, 1.1f), new Vector2(0.3f, 1.15f), new Vector2(0f, 0.8f), new Vector2(-0.5f, 1f));
        }
        // 如果是流出河流的河口(翻转uv)
        else
        {
            estuaries.AddQuadUV2(new Vector2(-0.5f, -0.2f), new Vector2(0.3f, -0.35f), new Vector2(0f, 0f), new Vector2(0.5f, -0.3f));
            estuaries.AddTriangleUV2(new Vector2(0.5f, -0.3f), new Vector2(0f, 0f), new Vector2(1f, 0f));
            estuaries.AddQuadUV2(new Vector2(0.5f, -0.3f), new Vector2(0.7f, -0.35f), new Vector2(1f, 0f), new Vector2(1.5f, -0.2f));
        }
    }
Exemple #19
0
    void Triangulate(HexDirection direction, HexCell cell)
    {
        Vector3 center      = cell.Position;
        Vector3 v1          = center + HexMetrics.GetFirstInnerCorner(direction);
        Vector3 v2          = center + HexMetrics.GetSecondInnerCorner(direction);
        Vector3 v1OuterBump = center + HexMetrics.GetFirstBumpOuterCorner(direction);
        Vector3 v2OuterBump = center + HexMetrics.GetSecondBumpOuterCorner(direction);

        Vector3 indices;

        indices.x = indices.y = indices.z = cell.Index;

        terrain.AddTriangle(center, v1, v2);
        terrain.AddTriangleCellData(indices, weights1);

        terrain.AddQuad(v1, v2, v1OuterBump, v2OuterBump);
        if (cell.IsUnderwater)
        {
            terrain.AddQuadCellData(indices, weights1, weights1);
        }
        else
        {
            terrain.AddQuadCellData(indices, terrainColorBump, terrainColorBump);
        }

        if (direction <= HexDirection.SE)
        {
            TriangulateConnection(direction, cell, v1OuterBump, v2OuterBump);
        }

        if (cell.IsUnderwater)
        {
            TriangulateWater(direction, cell, center);
        }

        if (!cell.IsUnderwater)
        {
            features.AddFeature(cell, (center + v1 + v2) * (1f / 3f));
        }
    }
Exemple #20
0
    private void AddWallSegment(Vector3 nearLeft, Vector3 farLeft, Vector3 nearRight, Vector3 farRight)
    {
        nearLeft  = HexMetrics.Perturb(nearLeft);
        farLeft   = HexMetrics.Perturb(farLeft);
        nearRight = HexMetrics.Perturb(nearRight);
        farRight  = HexMetrics.Perturb(farRight);

        Vector3 left  = HexMetrics.WallLerp(nearLeft, farLeft);
        Vector3 right = HexMetrics.WallLerp(nearRight, farRight);

        Vector3 leftThicknessOffset  = HexMetrics.WallThicknessOffset(nearLeft, farLeft);
        Vector3 rightThicknessOffset = HexMetrics.WallThicknessOffset(nearRight, farRight);
        float   leftTop  = left.y + HexMetrics.wallHeight;
        float   rightTop = right.y + HexMetrics.wallHeight;

        Vector3 v1;
        Vector3 v2;
        Vector3 v3 = v1 = left - leftThicknessOffset;
        Vector3 v4 = v2 = right - rightThicknessOffset;

        v3.y = leftTop;
        v4.y = rightTop;
        walls.AddQuad(v1, v2, v3, v4);

        Vector3 t1 = v3;
        Vector3 t2 = v4;

        v1   = v3 = left + leftThicknessOffset;
        v2   = v4 = right + rightThicknessOffset;
        v3.y = leftTop;
        v4.y = rightTop;

        walls.AddQuad(v2, v1, v4, v3);
        walls.AddQuad(t1, t2, v3, v4);
    }
Exemple #21
0
    private void TriangulateEdgeStrip(EdgeVertices e1, Color c1, EdgeVertices e2, Color c2, bool hasWall = false)
    {
        _terrain.AddQuad(e1.v1, e1.v2, e2.v1, e2.v2);
        _terrain.AddQuadColor(c1, c2);
        _terrain.AddQuad(e1.v2, e1.v3, e2.v2, e2.v3);
        _terrain.AddQuadColor(c1, c2);
        _terrain.AddQuad(e1.v3, e1.v4, e2.v3, e2.v4);
        _terrain.AddQuadColor(c1, c2);
        _terrain.AddQuad(e1.v4, e1.v5, e2.v4, e2.v5);
        _terrain.AddQuadColor(c1, c2);

        if (hasWall)
        {
            TriangulateWallSegment(e1.v2, e1.v3, e1.v4, e2.v2, e2.v3, e2.v4);
        }
    }
Exemple #22
0
 void TriangulateRiverQuad(Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4, float y1, float y2, float v, bool reversed, Vector3 indices)
 {
     v1.y = v2.y = y1;
     v3.y = v4.y = y2;
     rivers.AddQuad(v1, v2, v3, v4);
     if (reversed)
     {
         rivers.AddQuadUV(1f, 0f, 0.8f - v, 0.6f - v);
     }
     else
     {
         rivers.AddQuadUV(0f, 1f, v, v + 0.2f);
     }
     rivers.AddQuadCellData(indices, weights1, weights2);
 }
Exemple #23
0
    void TriangulateCornerTerraces(Vector3 begin, HexCell beginCell,
                                   Vector3 left, HexCell leftCell,
                                   Vector3 right, HexCell rightCell)
    {
        Vector3 v3 = HexMetrics.TerraceLerp(begin, left, 1);
        Vector3 v4 = HexMetrics.TerraceLerp(begin, right, 1);
        Color   c3 = HexMetrics.TerraceLerp(beginCell.Color, leftCell.Color, 1);
        Color   c4 = HexMetrics.TerraceLerp(beginCell.Color, rightCell.Color, 1);

        terrain.AddTriangle(begin, v3, v4);
        terrain.AddTriangleColor(beginCell.Color, c3, c4);

        terrain.AddQuad(v3, v4, left, right);
        terrain.AddQuadColor(c3, c4, leftCell.Color, rightCell.Color);
    }
Exemple #24
0
    /*
     * 连接三角形  针对left right都是梯田的
     */
    void TriangulateCornerTerraces(
        Vector3 begin, HexCell beginCell,
        Vector3 left, HexCell leftCell,
        Vector3 right, HexCell rightCell)
    {
        //在slope-slope-flat类型中,和平台的插值TriangulateEdgeTerraces方法一样
        Vector3 v3 = HexMetrics.TerraceLerp(begin, left, 1);
        Vector3 v4 = HexMetrics.TerraceLerp(begin, right, 1);
        Color   c3 = HexMetrics.TerraceLerp(color1, color2, 1);
        Color   c4 = HexMetrics.TerraceLerp(color1, color3, 1);
        //添加地形贴图UV
        Vector3 types;

        types.x = beginCell.TerrainTypeIndex;
        types.y = leftCell.TerrainTypeIndex;
        types.z = rightCell.TerrainTypeIndex;

        terrain.AddTriangle(begin, v3, v4);
        terrain.AddTriangleColor(color1, c3, c4);
        terrain.AddTriangleTerrainTypes(types);

        for (int i = 2; i < HexMetrics.terraceSteps; i++)
        {
            Vector3 v1 = v3;
            Vector3 v2 = v4;
            Color   c1 = c3;
            Color   c2 = c4;
            v3 = HexMetrics.TerraceLerp(begin, left, i);
            v4 = HexMetrics.TerraceLerp(begin, right, i);
            c3 = HexMetrics.TerraceLerp(color1, color2, i);
            c4 = HexMetrics.TerraceLerp(color1, color3, i);
            terrain.AddQuad(v1, v2, v3, v4);
            terrain.AddQuadColor(c1, c2, c3, c4);
            terrain.AddQuadTerrainTypes(types);
        }
        terrain.AddQuad(v3, v4, left, right);
        terrain.AddQuadColor(c3, c4, color2, color3);
        terrain.AddQuadTerrainTypes(types);
    }
Exemple #25
0
    /// <summary>
    /// 三角化角部连接,当角部三角形的边是两个斜坡与一个平地时
    /// </summary>
    /// <param name="begin"></param>
    /// <param name="beginCell"></param>
    /// <param name="left"></param>
    /// <param name="leftCell"></param>
    /// <param name="right"></param>
    /// <param name="rightCell"></param>
    void TriangulateCornerTerraces(Vector3 begin, HexCell beginCell, Vector3 left, HexCell leftCell, Vector3 right, HexCell rightCell)
    {
        Vector3 v3 = HexMetrics.TerraceLerp(begin, left, 1);
        Vector3 v4 = HexMetrics.TerraceLerp(begin, right, 1);
        Color   w3 = HexMetrics.TerraceLerp(weights1, weights2, 1);
        Color   w4 = HexMetrics.TerraceLerp(weights1, weights3, 1);

        Vector3 indices;

        indices.x = beginCell.Index;
        indices.y = leftCell.Index;
        indices.z = rightCell.Index;

        terrain.AddTriangle(begin, v3, v4);
        terrain.AddTriangleCellData(indices, weights1, w3, w4);
        //terrain.AddTriangleColor(color1, c3, c4);
        //terrain.AddTriangulateTerrainType(types);

        for (int i = 2; i < HexMetrics.terraceSteps; i++)
        {
            Vector3 v1 = v3;
            Vector3 v2 = v4;
            Color   w1 = w3;
            Color   w2 = w4;
            v3 = HexMetrics.TerraceLerp(begin, left, i);
            v4 = HexMetrics.TerraceLerp(begin, right, i);
            w3 = HexMetrics.TerraceLerp(weights1, weights2, i);
            w4 = HexMetrics.TerraceLerp(weights1, weights3, i);
            terrain.AddQuad(v1, v2, v3, v4);
            terrain.AddQuadCellData(indices, w1, w2, w3, w4);
            //terrain.AddQuadColor(c1, c2, c3, c4);
            //terrain.AddQuadTerrainType(types);
        }

        terrain.AddQuad(v3, v4, left, right);
        terrain.AddQuadCellData(indices, w3, w4, weights2, weights3);
        //terrain.AddQuadColor(c3, c4, color2, color3);
        //terrain.AddQuadTerrainType(types);
    }
Exemple #26
0
    /// <summary>
    /// 三角化河流四边形
    /// </summary>
    /// <param name="v1">自身六边形内的顶点</param>
    /// <param name="v2">自身六边形内的顶点</param>
    /// <param name="v3">邻居六边形内的顶点</param>
    /// <param name="v4">邻居六边形内的顶点</param>
    /// <param name="y1">自身高度(河水平面)</param>
    /// <param name="y2">邻居高度(河水平面)</param>
    /// <param name="v">UV坐标的V</param>
    /// <param name="reversed"></param>
    void TriangulateRiverQuad(Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4, float y1, float y2, float v, bool reversed, Vector3 indices)
    {
        v1.y = v2.y = y1;
        v3.y = v4.y = y2;
        // 添加顶点
        rivers.AddQuad(v1, v2, v3, v4);

        // 添加UV坐标(把一个六边形内的河水(六边形内四个四边形,加上桥,总共五个四边形)
        // UV坐标的v分为五等分:0~0.2, 0.2~0.4, 0.4~0.6, 0.6~0.8, 0.8~1)
        if (reversed)
        {
            rivers.AddQuadUV(1f, 0f, 0.8f - v, 0.6f - v);   // 流入河流
        }
        else
        {
            rivers.AddQuadUV(0f, 1f, v, v + 0.2f);          // 流出河流
        }

        rivers.AddQuadCellData(indices, weights1, weights2);
    }
Exemple #27
0
    void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e)
    {
        //outer walls
        Vector3 centerL, centerR;

        if (cell.HasRiverThroughEdge(direction.Opposite()))
        {
            centerL = center +
                      HexMetric.GetFirstSolidCorner(direction.Previous()) * 0.25f;
            centerR = center +
                      HexMetric.GetSecondSolidCorner(direction.Next()) * 0.25f;
        }
        // sharp turns
        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;
        }
        // two way turns
        else if (cell.HasRiverThroughEdge(direction.Next2()))
        {
            centerL = center;
            centerR = center + HexMetric.GetSolidEdgeMiddle(direction.Next()) * (0.5f * HexMetric.innerToOuter);
        }
        else
        {
            centerL = center + HexMetric.GetSolidEdgeMiddle(direction.Previous()) * (0.5f * HexMetric.innerToOuter);
            centerR = center;
        }

        //mid point of channel
        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;
        //fill area
        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);

        //river water quads
        if (!cell.IsUnderwater)
        {
            bool reversed = cell.IncomingRiver == direction;

            TriangulateRiverQuad(centerL, centerR, m.v2, m.v4, cell.RiverSurfaceY, 0.4f, reversed);
            TriangulateRiverQuad(m.v2, m.v4, e.v2, e.v4, cell.RiverSurfaceY, 0.6f, reversed);
        }
    }
    /// <summary>
    /// Creates the triangles for a side of the hexagon, with river passing through (incoming and outgoing river) at this side.
    /// </summary>
    void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e)
    {
        Vector3 centerL, centerR;

        if (cell.HasRiverThroughEdge(direction.Opposite()))           // If river flows forward through the cell
        // Extend center into line
        {
            centerL = center + HexMetrics.GetFirstSolidCorner(direction.Previous()) * 0.25f;
            centerR = center + HexMetrics.GetSecondSolidCorner(direction.Next()) * 0.25f;
        }
        else if (cell.HasRiverThroughEdge(direction.Next()))           // If river bends sharply in next dir
        {
            centerL = center;
            centerR = Vector3.Lerp(center, e.v5, 2f / 3f);
        }
        else if (cell.HasRiverThroughEdge(direction.Previous()))           // If river bends sharply in prev dir
        {
            centerL = Vector3.Lerp(center, e.v1, 2f / 3f);
            centerR = center;
        }
        else if (cell.HasRiverThroughEdge(direction.Next2()))           //  River bends smoothly to next.next dir
        {
            centerL = center;
            centerR = center + HexMetrics.GetSolidEdgeMiddle(direction.Next()) * (0.5f * HexMetrics.InnerToOuter);
        }
        else           //  River bends smoothly to previous.previous dir
        {
            centerL = center + HexMetrics.GetSolidEdgeMiddle(direction.Previous()) * (0.5f * HexMetrics.InnerToOuter);
            centerR = center;
        }

        center = Vector3.Lerp(centerL, centerR, 0.5f);         // Average center to serve all cases

        // Edge 1/2 the way from edge and cell center
        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;         // Lower middle edge and center to river bed

        TriangulateEdgeStrip(m, weights1, cell.Index, e, weights1, cell.Index);

        // Final gap between the middle edge and the center
        // Geo
        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 + Terrain 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)             // No river water surface when underwater, river bed allowed
        // River water surface
        {
            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);
        }
    }
Exemple #29
0
    void TriangulateEstuary(EdgeVertices e1, EdgeVertices e2, bool incomingRiver, Vector3 indices)
    {
        waterShore.AddTriangle(e2.v1, e1.v2, e1.v1);
        waterShore.AddTriangle(e2.v5, e1.v5, e1.v4);
        waterShore.AddTriangleUV(
            new Vector2(0f, 1f),
            new Vector2(0f, 0f),
            new Vector2(0f, 0f)
            );
        waterShore.AddTriangleUV(
            new Vector2(0f, 1f),
            new Vector2(0f, 0f),
            new Vector2(0f, 0f)
            );
        waterShore.AddTriangleCellData(indices, weights2, weights1, weights1);
        waterShore.AddTriangleCellData(indices, weights2, weights1, weights1);

        estuaries.AddQuad(e2.v1, e1.v2, e2.v2, e1.v3);
        estuaries.AddTriangle(e1.v3, e2.v2, e2.v4);
        estuaries.AddQuad(e1.v3, e1.v4, e2.v4, e2.v5);
        estuaries.AddQuadUV(
            new Vector2(0f, 1f),
            new Vector2(0f, 0f),
            new Vector2(1f, 1f),
            new Vector2(0f, 0f)
            );
        estuaries.AddTriangleUV(
            new Vector2(0f, 0f),
            new Vector2(1f, 1f),
            new Vector2(1f, 1f)
            );
        estuaries.AddQuadUV(
            new Vector2(0f, 0f),
            new Vector2(0f, 0f),
            new Vector2(1f, 1f),
            new Vector2(0f, 1f)
            );
        estuaries.AddQuadCellData(indices, weights2, weights1, weights2, weights1);
        estuaries.AddTriangleCellData(indices, weights2, weights1, weights2);
        estuaries.AddQuadCellData(indices, weights1, weights2);

        if (incomingRiver)
        {
            estuaries.AddQuadUV2(
                new Vector2(1.5f, 1f),
                new Vector2(0.7f, 1.15f),
                new Vector2(1f, 0.8f),
                new Vector2(0.5f, 1.1f)
                );
            estuaries.AddTriangleUV2(
                new Vector2(0.5f, 1.1f),
                new Vector2(1f, 0.8f),
                new Vector2(0f, 0.8f)
                );
            estuaries.AddQuadUV2(
                new Vector2(0.5f, 1.1f),
                new Vector2(0.3f, 1.15f),
                new Vector2(0f, 0.8f),
                new Vector2(-0.5f, 1f)
                );
        }
        else
        {
            estuaries.AddQuadUV2(
                new Vector2(-0.5f, -0.3f),
                new Vector2(0.3f, -0.35f),
                new Vector2(0f, 0f),
                new Vector2(0.5f, -0.3f)
                );
            estuaries.AddTriangleUV2(
                new Vector2(0.5f, -0.3f),
                new Vector2(0f, 0f),
                new Vector2(1f, 0f)
                );
            estuaries.AddQuadUV2(
                new Vector2(0.5f, -0.3f),
                new Vector2(0.7f, -0.35f),
                new Vector2(1f, 0f),
                new Vector2(1.5f, -0.2f)
                );
        }
    }
Exemple #30
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;
        for (int i = 0; i < 4; i++)
        {
            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);
            for (int i = 0; i < 4; i++)
            {
                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);
        }
    }