Beispiel #1
0
        // Triangulate a corner with half terraces, half flat - Cliff on the left
        void TriangulateCornerCliffTerraces(Vector3 begin, HexCell beginCell, Vector3 left, HexCell leftCell, Vector3 right, HexCell rightCell)
        {
            float b = 1f / (leftCell.Elevation - beginCell.Elevation);

            if (b < 0)
            {
                b = -b;
            }
            Vector3 boundary      = Vector3.Lerp(HexMetrics.Perturb(begin), HexMetrics.Perturb(left), b); // boundary is on a pertubed slope
            Color   boundaryColor = Color.Lerp(beginCell.Color, leftCell.Color, b);

            TriangulateBoundaryTriangle(right, rightCell, begin, beginCell, boundary, boundaryColor);

            if (leftCell.GetEdgeType(rightCell) == HexEdgeType.Slope)
            {
                TriangulateBoundaryTriangle(left, leftCell, right, rightCell, boundary, boundaryColor);
            }
            else
            {
                terrain.AddTriangleUnpertubed(HexMetrics.Perturb(left), HexMetrics.Perturb(right), boundary);
                terrain.AddTriangleColor(leftCell.Color, rightCell.Color, boundaryColor);
            }
        }
        private 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);

            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.AddQuad(v3, v4, left, right);
            terrain.AddQuadCellData(indices, w3, w4, weights2, weights3);
        }
        private void TriangulateEdgeTerraces(
            EdgeVertices begin, HexCell beginCell,
            EdgeVertices end, HexCell endCell,
            bool hasRoad
            )
        {
            EdgeVertices e2 = EdgeVertices.TerraceLerp(begin, end, 1);
            Color        w2 = HexMetrics.TerraceLerp(weights1, weights2, 1);
            float        i1 = beginCell.Index;
            float        i2 = endCell.Index;

            TriangulateEdgeStrip(begin, weights1, i1, e2, w2, i2, hasRoad);

            for (int i = 2; i < HexMetrics.terraceSteps; i++)
            {
                EdgeVertices e1 = e2;
                Color        w1 = w2;
                e2 = EdgeVertices.TerraceLerp(begin, end, i);
                w2 = HexMetrics.TerraceLerp(weights1, weights2, i);
                TriangulateEdgeStrip(e1, w1, i1, e2, w2, i2, hasRoad);
            }

            TriangulateEdgeStrip(e2, w2, i1, end, weights2, i2, hasRoad);
        }
Beispiel #4
0
        // Make a terrace in a corner, each terrace end in the boundary
        void TriangulateBoundaryTriangle(Vector3 begin, HexCell beginCell, Vector3 left, HexCell leftCell, Vector3 boundary, Color boundaryColor)
        {
            Vector3 v2 = HexMetrics.Perturb(HexMetrics.TerraceLerp(begin, left, 1));
            Color   c2 = HexMetrics.TerraceLerp(beginCell.Color, leftCell.Color, 1);

            // The first step is a triangle
            terrain.AddTriangleUnpertubed(HexMetrics.Perturb(begin), v2, boundary);
            terrain.AddTriangleColor(beginCell.Color, c2, boundaryColor);

            // All the steps are triangles
            for (int i = 2; i < HexMetrics.terraceSteps; i++)
            {
                Vector3 v1 = v2;
                Color   c1 = c2;
                v2 = HexMetrics.Perturb(HexMetrics.TerraceLerp(begin, left, i));
                c2 = HexMetrics.TerraceLerp(beginCell.Color, leftCell.Color, i);
                terrain.AddTriangleUnpertubed(v1, v2, boundary);
                terrain.AddTriangleColor(c1, c2, boundaryColor);
            }

            // The last step is a triangle
            terrain.AddTriangleUnpertubed(v2, HexMetrics.Perturb(left), boundary);
            terrain.AddTriangleColor(c2, leftCell.Color, boundaryColor);
        }
Beispiel #5
0
        void TriangulateEdgeTerraces(Vector3 beginLeft, Vector3 beginRight, HexCell beginCell, Vector3 endLeft, Vector3 endRight, HexCell endCell)
        {
            Vector3 v3 = HexMetrics.TerraceLerp(beginLeft, endLeft, 1);
            Vector3 v4 = HexMetrics.TerraceLerp(beginRight, endRight, 1);
            Color   c2 = HexMetrics.TerraceLerp(beginCell.Color, endCell.Color, 1);

            AddQuad(beginLeft, beginRight, v3, v4);
            AddQuadColor(beginCell.Color, c2);

            for (int i = 2; i < HexMetrics.TerraceSteps; i++)
            {
                Vector3 v1 = v3;
                Vector3 v2 = v4;
                Color   c1 = c2;
                v3 = HexMetrics.TerraceLerp(beginLeft, endLeft, i);
                v4 = HexMetrics.TerraceLerp(beginRight, endRight, i);
                c2 = HexMetrics.TerraceLerp(beginCell.Color, endCell.Color, i);
                AddQuad(v1, v2, v3, v4);
                AddQuadColor(c1, c2);
            }

            AddQuad(v3, v4, endLeft, endRight);
            AddQuadColor(c2, endCell.Color);
        }
        private void TriangulateConnection(
            HexDirection direction, HexCell cell, EdgeVertices e1
            )
        {
            HexCell neighbor = cell.GetNeighbor(direction);

            if (neighbor == null)
            {
                return;
            }

            Vector3 bridge = HexMetrics.GetBridge(direction);

            bridge.y = neighbor.Position.y - cell.Position.y;
            EdgeVertices e2 = new EdgeVertices(
                e1.v1 + bridge,
                e1.v5 + bridge
                );

            bool hasRiver = cell.HasRiverThroughEdge(direction);
            bool hasRoad  = cell.HasRoadThroughEdge(direction);

            if (hasRiver)
            {
                e2.v3.y = neighbor.StreamBedY;
                Vector3 indices;
                indices.x = indices.z = cell.Index;
                indices.y = neighbor.Index;

                if (!cell.IsUnderwater)
                {
                    if (!neighbor.IsUnderwater)
                    {
                        TriangulateRiverQuad(
                            e1.v2, e1.v4, e2.v2, e2.v4,
                            cell.RiverSurfaceY, neighbor.RiverSurfaceY, 0.8f,
                            cell.HasIncomingRiver && cell.IncomingRiver == direction, indices
                            );
                    }
                    else if (cell.Elevation > neighbor.WaterLevel)
                    {
                        TriangulateWaterfallInWater(
                            e1.v2, e1.v4, e2.v2, e2.v4,
                            cell.RiverSurfaceY, neighbor.RiverSurfaceY,
                            neighbor.WaterSurfaceY, indices
                            );
                    }
                }
                else if (!neighbor.IsUnderwater && neighbor.Elevation > cell.WaterLevel)
                {
                    TriangulateWaterfallInWater(
                        e2.v4, e2.v2, e1.v4, e1.v2,
                        neighbor.RiverSurfaceY, cell.RiverSurfaceY,
                        cell.WaterSurfaceY, indices
                        );
                }
            }

            if (cell.GetEdgeType(direction) == HexEdgeType.Slope)
            {
                TriangulateEdgeTerraces(e1, cell, e2, neighbor, hasRoad);
            }
            else
            {
                TriangulateEdgeStrip(
                    e1, weights1, cell.Index,
                    e2, weights2, neighbor.Index, hasRoad
                    );
            }

            features.AddWall(e1, cell, e2, neighbor, hasRiver, hasRoad);

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

            if (direction <= HexDirection.E && nextNeighbor != null)
            {
                Vector3 v5 = e1.v5 + HexMetrics.GetBridge(direction.Next());
                v5.y = nextNeighbor.Position.y;

                if (cell.Elevation <= neighbor.Elevation)
                {
                    if (cell.Elevation <= nextNeighbor.Elevation)
                    {
                        TriangulateCorner(
                            e1.v5, cell, e2.v5, neighbor, v5, nextNeighbor
                            );
                    }
                    else
                    {
                        TriangulateCorner(
                            v5, nextNeighbor, e1.v5, cell, e2.v5, neighbor
                            );
                    }
                }
                else if (neighbor.Elevation <= nextNeighbor.Elevation)
                {
                    TriangulateCorner(
                        e2.v5, neighbor, v5, nextNeighbor, e1.v5, cell
                        );
                }
                else
                {
                    TriangulateCorner(
                        v5, nextNeighbor, e1.v5, cell, e2.v5, neighbor
                        );
                }
            }
        }
        private void TriangulateWithRiver(
            HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e
            )
        {
            Vector3 centerL, centerR;

            if (cell.HasRiverThroughEdge(direction.Opposite()))
            {
                centerL = center +
                          HexMetrics.GetFirstSolidCorner(direction.Previous()) * 0.25f;
                centerR = center +
                          HexMetrics.GetSecondSolidCorner(direction.Next()) * 0.25f;
            }
            else if (cell.HasRiverThroughEdge(direction.Next()))
            {
                centerL = center;
                centerR = Vector3.Lerp(center, e.v5, 2f / 3f);
            }
            else if (cell.HasRiverThroughEdge(direction.Previous()))
            {
                centerL = Vector3.Lerp(center, e.v1, 2f / 3f);
                centerR = center;
            }
            else if (cell.HasRiverThroughEdge(direction.Next2()))
            {
                centerL = center;
                centerR = center +
                          HexMetrics.GetSolidEdgeMiddle(direction.Next()) *
                          (0.5f * HexMetrics.innerToOuter);
            }
            else
            {
                centerL = center +
                          HexMetrics.GetSolidEdgeMiddle(direction.Previous()) *
                          (0.5f * HexMetrics.innerToOuter);
                centerR = center;
            }
            center = Vector3.Lerp(centerL, centerR, 0.5f);

            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
                    );
            }
        }
        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;

            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;
            }
            else
            {
                HexDirection middle;
                if (previousHasRiver)
                {
                    middle = direction.Next();
                }
                else if (nextHasRiver)
                {
                    middle = direction.Previous();
                }
                else
                {
                    middle = direction;
                }
                if (
                    !cell.HasRoadThroughEdge(middle) &&
                    !cell.HasRoadThroughEdge(middle.Previous()) &&
                    !cell.HasRoadThroughEdge(middle.Next())
                    )
                {
                    return;
                }
                Vector3 offset = HexMetrics.GetSolidEdgeMiddle(middle);
                roadCenter += offset * 0.25f;

                if (direction == middle &&
                    cell.HasRoadThroughEdge(direction.Opposite()))
                {
                    features.AddBridge(
                        roadCenter,
                        center - offset * (HexMetrics.innerToOuter * 0.7f)
                        );
                }
            }

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

            TriangulateRoad(roadCenter, mL, mR, e, hasRoadThroughEdge, cell.Index);
            if (previousHasRiver)
            {
                TriangulateRoadEdge(roadCenter, center, mL, cell.Index);
            }
            if (nextHasRiver)
            {
                TriangulateRoadEdge(roadCenter, mR, center, cell.Index);
            }
        }
        private void TriangulateWaterShore(
            HexDirection direction, HexCell cell, HexCell neighbor, Vector3 center
            )
        {
            EdgeVertices e1 = new EdgeVertices(
                center + HexMetrics.GetFirstWaterCorner(direction),
                center + HexMetrics.GetSecondWaterCorner(direction)
                );

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

            Vector3 indices;

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

            Vector3 center2 = neighbor.Position;

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

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

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

            if (nextNeighbor != null)
            {
                Vector3 center3 = nextNeighbor.Position;
                if (nextNeighbor.ColumnIndex < cell.ColumnIndex - 1)
                {
                    center3.x += HexMetrics.wrapSize * HexMetrics.innerDiameter;
                }
                else if (nextNeighbor.ColumnIndex > cell.ColumnIndex + 1)
                {
                    center3.x -= HexMetrics.wrapSize * HexMetrics.innerDiameter;
                }
                Vector3 v3 = center3 + (nextNeighbor.IsUnderwater ?
                                        HexMetrics.GetFirstWaterCorner(direction.Previous()) :
                                        HexMetrics.GetFirstSolidCorner(direction.Previous()));
                v3.y = center.y;
                waterShore.AddTriangle(e1.v5, e2.v5, v3);
                waterShore.AddTriangleUV(
                    new Vector2(0f, 0f),
                    new Vector2(0f, 1f),
                    new Vector2(0f, nextNeighbor.IsUnderwater ? 0f : 1f)
                    );
                indices.z = nextNeighbor.Index;
                waterShore.AddTriangleCellData(
                    indices, weights1, weights2, weights3
                    );
            }
        }
Beispiel #10
0
        public Mesh ElevatedTileHexagon(HexMetrics metrics, HexMap hexMap, int column, int row, Mesh recycleMesh = null)
        {
            ClearAndSetup("Hexagon Tile With Elevation", recycleMesh);

            Vector3 center = HexUtils.PositionFromCoordinates(column, row, metrics.tileSize);

            int elevation = hexMap.GetElevationAt(column, row);

            float elevationHeight = metrics.elevationStepHeight * elevation;

            Color baseColor = hexMap.tileset.GetColorForElevation(elevation, metrics.maxElevation);

            float centerHeight = metrics.XZPositionToHeight(center);

            float[] cornerHeights = new float[6];
            foreach (var corner in HexCornerUtils.AllCorners())
            {
                Vector3 vertex = HexUtils.CornerPosition((int)corner) * metrics.tileSize;
                cornerHeights[corner.GetInt()] = metrics.XZPositionToHeight(center + vertex);
            }

            #region Base Hexagon

            float baseHexagonPercentage = metrics.tileInnerRadiusPercent;

            // Add vertex data for each corner first in order to reduce redundancy (18 vertices -> 7)
            // Not making triangles yet
            foreach (HexCorner corner in HexCornerUtils.AllCorners())
            {
                // Vertice w/ height
                //Vector3 cornerPoint = SpokePoint(metrics, corner, baseHexagonPercentage, centerHeight, cornerHeights);
                // Base the height of the 'spokes' on the straight line from the center out to the corner of the whole tile
                Vector3 cornerVertex = HexUtils.CornerPosition((int)corner) * metrics.tileSize * baseHexagonPercentage;

                float projectedSpokeHeight = (cornerHeights[corner.GetInt()] - centerHeight)
                                             * baseHexagonPercentage;
                float   vertexHeight    = centerHeight + projectedSpokeHeight;
                Vector3 cornerPoint     = cornerVertex + Vector3.up * (vertexHeight * metrics.mapHeight + elevationHeight);
                float   textureGradient = vertexHeight;
                AddHexPointData(metrics, cornerPoint, center, baseColor, textureGradient);
            }

            // Add the center point last just so that we can use the HexCorner enums as indexes and the center is @ 6
            int Center = 6;             // just for readability
            // UV
            uvs.Add(metrics.XZPositionToUV(center));

            // Vertice
            Vector3 centerVertex = new Vector3(0, centerHeight * metrics.mapHeight + elevationHeight, 0);
            vertices.Add(centerVertex);

            // Color
            colors.Add(baseColor);

            // Gradient
            uvs2.Add(new Vector2(centerHeight, 0));

            // Make triangles
            foreach (HexCorner corner in HexCornerUtils.AllCorners())
            {
                triangles.Add((int)corner.Next());                 // Next first because of normals
                triangles.Add((int)corner);
                triangles.Add(Center);
            }

            #endregion

            // The starting index of the points for the outer ring
            int ringStartIndex = vertices.Count;             // should be 7 here

            // ----------Add another ring to the hexagon
            #region First Ring

            float firstRingPercentage = metrics.tileOuterRadiusPercent;

            // Add vertex data for each outside corner
            // Not making triangles yet
            // Add three points for each corner: the actual outside corner and then the two bridge points
            foreach (HexCorner corner in HexCornerUtils.AllCorners())
            {
                HexDirection direction = corner.GetDirection();

                float theta = HexUtils.CornerAngle((int)corner);

                //// We need to account for the three walls connecting to this corner:
                //// the wall on this hex going left,
                //// the wall on this hex going right,
                //// and the wall adjacent to this hex running out and away
                //bool leftWall = hexMap.IsWallAt(column, row, corner.GetDirection());
                //bool rightWall = hexMap.IsWallAt(column, row, corner.GetDirection().Last());
                //// move to the hex left of the given corner, turn two directions CW and check that wall
                //bool awayWall = hexMap.IsWallAt(HexUtils.MoveFrom(column, row, corner.GetDirection()), corner.GetDirection().Last2());



                // -------Actual Corner---------- -
                {
                    Vector3 cornerVertex = HexUtils.CornerPosition((int)corner) * metrics.tileSize * firstRingPercentage;

                    float nextNeighborElevationHeight = metrics.elevationStepHeight *
                                                        hexMap.GetElevationAt(HexUtils.MoveFrom(column, row, direction));
                    float lastNeighborElevationHeight = metrics.elevationStepHeight *
                                                        hexMap.GetElevationAt(HexUtils.MoveFrom(column, row, direction.Last()));
                    float heightModFromElevation =
                        (elevationHeight + nextNeighborElevationHeight + lastNeighborElevationHeight) * 0.33f;

                    float projectedSpokeHeight = (cornerHeights[corner.GetInt()] - centerHeight)
                                                 * firstRingPercentage;
                    float   vertexHeight = centerHeight + projectedSpokeHeight;
                    Vector3 cornerPoint  = cornerVertex +
                                           Vector3.up * (vertexHeight * metrics.mapHeight + heightModFromElevation);
                    float textureGradient = vertexHeight;

                    bool  isWall     = hexMap.IsWallAt(column, row, direction.Last());
                    Color slopeColor = baseColor;
                    if (isWall)
                    {
                        slopeColor = hexMap.tileset.steepSlopeColor;
                    }

                    AddHexPointData(metrics, cornerPoint, center, slopeColor, textureGradient);
                }

                //// ------- CCW Bridge Point -----------
                {
                    var fromCorner       = corner;
                    var towardCorner     = corner.Next();
                    var bridgePercentage = metrics.tileInnerRadiusPercent;

                    //Vector3 bridgePoint = BridgePoint(metrics, corner, corner.Next(), firstRingPercentage,
                    //	metrics.tileInnerRadiusPercent, centerVertex, cornerHeights);

                    float nextNeighborElevationHeight = metrics.elevationStepHeight *
                                                        hexMap.GetElevationAt(HexUtils.MoveFrom(column, row, direction));
                    float heightModFromElevation =
                        (elevationHeight + nextNeighborElevationHeight) * 0.5f;


                    Vector3 cornerVertex = HexUtils.CornerPosition((int)fromCorner) * metrics.tileSize;
                    cornerVertex = cornerVertex +
                                   Vector3.up * (cornerHeights[fromCorner.GetInt()] * metrics.mapHeight + heightModFromElevation);

                    Vector3 nextCornerPoint = HexUtils.CornerPosition(towardCorner.GetInt()) * metrics.tileSize;
                    nextCornerPoint = nextCornerPoint +
                                      Vector3.up * (cornerHeights[towardCorner.GetInt()] * metrics.mapHeight + heightModFromElevation);

                    Vector3 vector      = nextCornerPoint - cornerVertex;
                    float   bridgeMod   = 0.5f * (1f - bridgePercentage);
                    Vector3 bridgePoint = cornerVertex + vector * bridgeMod;

                    vector      = centerVertex - bridgePoint;
                    bridgePoint = bridgePoint + vector * (1f - firstRingPercentage);

                    bool  isWall     = hexMap.IsWallAt(column, row, direction);
                    Color slopeColor = baseColor;
                    if (isWall)
                    {
                        slopeColor = hexMap.tileset.steepSlopeColor;
                    }

                    AddHexPointData(metrics, bridgePoint, center, slopeColor, cornerHeights[corner.GetInt()]);
                }

                //// ------- CW Bridge Point -----------
                {
                    //Vector3 bridgePoint = BridgePoint(metrics, corner, corner.Last(), firstRingPercentage,
                    //	metrics.tileInnerRadiusPercent, centerVertex, cornerHeights);

                    var fromCorner       = corner;
                    var towardCorner     = corner.Last();
                    var bridgePercentage = metrics.tileInnerRadiusPercent;

                    //Vector3 bridgePoint = BridgePoint(metrics, corner, corner.Next(), firstRingPercentage,
                    //	metrics.tileInnerRadiusPercent, centerVertex, cornerHeights);

                    float neighborElevationHeight = metrics.elevationStepHeight *
                                                    hexMap.GetElevationAt(HexUtils.MoveFrom(column, row, direction.Last()));
                    float heightModFromElevation =
                        (elevationHeight + neighborElevationHeight) * 0.5f;

                    Vector3 cornerVertex = HexUtils.CornerPosition((int)fromCorner) * metrics.tileSize;
                    cornerVertex = cornerVertex +
                                   Vector3.up * (cornerHeights[fromCorner.GetInt()] * metrics.mapHeight + heightModFromElevation);

                    Vector3 nextCornerPoint = HexUtils.CornerPosition(towardCorner.GetInt()) * metrics.tileSize;
                    nextCornerPoint = nextCornerPoint + Vector3.up * (cornerHeights[towardCorner.GetInt()] * metrics.mapHeight + heightModFromElevation);

                    Vector3 vector      = nextCornerPoint - cornerVertex;
                    float   bridgeMod   = 0.5f * (1f - bridgePercentage);
                    Vector3 bridgePoint = cornerVertex + vector * bridgeMod;

                    vector      = centerVertex - bridgePoint;
                    bridgePoint = bridgePoint + vector * (1f - firstRingPercentage);

                    bool  isWall     = hexMap.IsWallAt(column, row, direction.Last());
                    Color slopeColor = baseColor;
                    if (isWall)
                    {
                        slopeColor = hexMap.tileset.steepSlopeColor;
                    }
                    AddHexPointData(metrics, bridgePoint, center, slopeColor, cornerHeights[corner.GetInt()]);
                }
            }

            // Make triangles, accounting for one corner and one side at a time

            // we actually need quads, so pairs of triangles
            foreach (HexCorner corner in HexCornerUtils.AllCorners())
            {
                // inside point is [corner], outside point is [corner * 3 + ORStart]
                int outerCorner = (int)corner * 3 + ringStartIndex + 0;
                // left bridge point is [corner * 3 + ORStart + 1], right bridge point is [corner * 3 + ORStart + 2]
                int rightBridgePoint = (int)corner * 3 + ringStartIndex + 2;
                int leftBridgePoint  = (int)corner * 3 + ringStartIndex + 1;
                // corner.Next() is the point CCW
                int nextRightBridgePoint = (int)corner.Next() * 3 + ringStartIndex + 2;

                // first half of the quad
                triangles.Add((int)corner);
                triangles.Add((int)corner.Next());
                triangles.Add(nextRightBridgePoint);

                // second half of the quad
                triangles.Add(nextRightBridgePoint);
                triangles.Add(leftBridgePoint);
                triangles.Add((int)corner);

                // span from the quad to the corner with a quad
                triangles.Add(leftBridgePoint);
                triangles.Add(outerCorner);
                triangles.Add((int)corner);

                // second part of corner span
                triangles.Add(rightBridgePoint);
                triangles.Add((int)corner);
                triangles.Add(outerCorner);
            }

            #endregion



            return(Build());
        }
Beispiel #11
0
        // Triangulate a cell for the direction given
        void Triangulate(HexDirection direction, HexCell cell)
        {
            Vector3      center = cell.Position;
            EdgeVertices e      = new EdgeVertices(center + HexMetrics.GetFirstSolidCorner(direction), center + HexMetrics.GetSecondSolidCorner(direction));

            if (cell.HasRiver)
            {
                if (cell.HasRiverThroughEdge(direction))
                {
                    e.v3.y = cell.StreamBedY;
                    if (cell.HasRiverBeginOrEnd)
                    {
                        TriangulateWithRiverBeginOrEnd(direction, cell, center, e);
                    }
                    else
                    {
                        TriangulateWithRiver(direction, cell, center, e);
                    }
                }
                else
                {
                    TriangulateAdjacentToRiver(direction, cell, center, e);
                }
            }
            else
            {
                TriangulateWithoutRiver(direction, cell, center, e);

                if (!cell.IsUnderwater && !cell.HasRoadThroughEdge(direction))
                {
                    features.AddFeature(cell, (center + e.v1 + e.v5) * (1f / 3f));
                }
            }

            // Make the connection with the neightbors
            if (direction <= HexDirection.SE)
            {
                TriangulateConnection(cell, direction, e);
            }

            if (cell.IsUnderwater)
            {
                TriangulateWater(direction, cell, center);
            }
        }
Beispiel #12
0
        void TriangulateWaterShore(HexDirection direction, HexCell cell, HexCell neighbor, Vector3 center)
        {
            // Triangulate as a fan
            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);

            // Triangulate the strip
            Vector3 center2 = neighbor.Position;

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

            if (cell.HasRiverThroughEdge(direction))
            {
                TriangulateEstuary(e1, e2, cell.HasIncomingRiver && cell.IncomingRiver == direction);
            }
            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);
            }

            // Don't forget the corner triangle
            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));
            }
        }
Beispiel #13
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 the road center in the opposite direction of river
            if (cell.HasRiverBeginOrEnd)
            {
                roadCenter += HexMetrics.GetSolidEdgeMiddle(cell.RiverBeginOrEndDirection.Opposite()) * (1f / 3f);
            }
            // Check if river is a straight
            else if (cell.IncomingRiver == cell.OutgoingRiver.Opposite())
            {
                Vector3 corner;
                if (previousHasRiver)
                {
                    // Skip triangulation if there is no road on this side on=f the river
                    if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Next()))
                    {
                        return;
                    }
                    corner = HexMetrics.GetSecondSolidCorner(direction);
                }
                else
                {
                    // Skip triangulation if there is no road on this side on=f the river
                    if (!hasRoadThroughEdge && !cell.HasRoadThroughEdge(direction.Previous()))
                    {
                        return;
                    }
                    corner = HexMetrics.GetFirstSolidCorner(direction);
                }
                roadCenter += corner * 0.5f;
                // Add bridge once per cell, if there is a road on both sides
                if (cell.IncomingRiver == direction.Next() && (cell.HasRoadThroughEdge(direction.Next2()) || cell.HasRoadThroughEdge(direction.Opposite())))
                {
                    features.AddBridge(roadCenter, center - corner * 0.5f);
                }
                center += corner * 0.25f;
            }
            // Check if river is a zigzag
            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;
            }
            // Check if we are inside of a curve
            else if (previousHasRiver && nextHasRiver)
            {
                if (!hasRoadThroughEdge)
                {
                    return;
                }
                Vector3 offset = HexMetrics.GetSolidEdgeMiddle(direction) * HexMetrics.innerToOutter;
                roadCenter += offset * 0.7f;
                center     += offset * 0.5f;
            }
            // We are outside of a curve
            else
            {
                HexDirection middle;
                if (previousHasRiver)
                {
                    middle = direction.Next();
                }
                else if (nextHasRiver)
                {
                    middle = direction.Previous();
                }
                else
                {
                    middle = direction;
                }
                if (!cell.HasRoadThroughEdge(middle.Previous()) && !cell.HasRoadThroughEdge(middle) && !cell.HasRoadThroughEdge(middle.Next()))
                {
                    return;
                }
                Vector3 offset = HexMetrics.GetSolidEdgeMiddle(middle);
                roadCenter += offset * 0.25f;
                // Add bridge once per cell, if there is a road on both sides
                if (direction == middle && cell.HasRoadThroughEdge(direction.Opposite()))
                {
                    features.AddBridge(roadCenter, center - offset * (HexMetrics.innerToOutter * 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);
            if (previousHasRiver)
            {
                TriangulateRoadEdge(roadCenter, center, mL);
            }
            if (nextHasRiver)
            {
                TriangulateRoadEdge(roadCenter, mR, center);
            }
        }
Beispiel #14
0
        // Fill the gap between each cell in the direction given
        void TriangulateConnection(HexCell cell, HexDirection direction, EdgeVertices e1)
        {
            HexCell neighbor = cell.GetNeighbor(direction);

            if (neighbor == null)
            {
                return;
            }

            // Build the bridge
            Vector3 bridge = HexMetrics.GetBridge(direction);

            bridge.y = neighbor.Position.y - cell.Position.y;
            EdgeVertices e2 = new EdgeVertices(e1.v1 + bridge, e1.v5 + bridge);

            bool hasRiver = cell.HasRiverThroughEdge(direction);
            bool hasRoad  = cell.HasRoadThroughEdge(direction);

            if (hasRiver)
            {
                e2.v3.y = neighbor.StreamBedY;
                if (!cell.IsUnderwater)
                {
                    if (!neighbor.IsUnderwater)
                    {
                        // Normal river
                        TriangulateRiverQuad(e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbor.RiverSurfaceY, 0.8f, cell.HasIncomingRiver && cell.IncomingRiver == direction);
                    }
                    else if (cell.Elevation > neighbor.WaterLevel)
                    {
                        // Waterfall from cell to neighbor
                        TriangulateWaterfallInWater(e1.v2, e1.v4, e2.v2, e2.v4, cell.RiverSurfaceY, neighbor.RiverSurfaceY, neighbor.WaterSurfaceY);
                    }
                }
                else if (!neighbor.IsUnderwater && neighbor.Elevation > cell.WaterLevel)
                {
                    // Waterfall from neighbor to cell
                    TriangulateWaterfallInWater(e2.v4, e2.v2, e1.v4, e1.v2, neighbor.RiverSurfaceY, cell.RiverSurfaceY, cell.WaterSurfaceY);
                }
            }

            if (cell.GetEdgeType(direction) == HexEdgeType.Slope)
            {
                TriangulateEdgeTerraces(e1, cell, e2, neighbor, hasRoad);
            }
            else
            {
                TriangulateEdgeStrip(e1, cell.Color, e2, neighbor.Color, hasRoad);
            }

            features.AddWall(e1, cell, e2, neighbor, hasRiver, hasRoad);

            // Filling the gap
            HexCell nextNeighbor = cell.GetNeighbor(direction.Next());

            if (direction <= HexDirection.E && nextNeighbor != null)
            {
                Vector3 v5 = e1.v5 + HexMetrics.GetBridge(direction.Next());
                v5.y = nextNeighbor.Position.y;

                // Find the lowest cell
                if (cell.Elevation <= neighbor.Elevation)
                {
                    if (cell.Elevation <= nextNeighbor.Elevation)
                    {
                        TriangulateCorner(e1.v5, cell, e2.v5, neighbor, v5, nextNeighbor); // cell is the lowest
                    }
                    else
                    {
                        TriangulateCorner(v5, nextNeighbor, e1.v5, cell, e2.v5, neighbor); // nextNeighbor is the lowest
                    }
                }
                else if (neighbor.Elevation <= nextNeighbor.Elevation)
                {
                    TriangulateCorner(e2.v5, neighbor, v5, nextNeighbor, e1.v5, cell); // neighbor is the lowest
                }
                else
                {
                    TriangulateCorner(v5, nextNeighbor, e1.v5, cell, e2.v5, neighbor); // nextNeighbor is the lowest
                }
            }
        }
Beispiel #15
0
 public HexEdgeType GetEdgeType(HexCell otherCell)
 {
     return(HexMetrics.GetEdgeType(Elevation, otherCell.Elevation));
 }
Beispiel #16
0
 public HexEdgeType GetEdgeType(HexDirection direction)
 {
     return(HexMetrics.GetEdgeType(Elevation, _neighbors[(int)direction].Elevation));
 }