private Vector2 GetRoadInterpolators( Hex source, HexDirections direction, Dictionary <HexDirections, bool> roadEdges ) { Vector2 interpolators; // if (hex.HasRoadThroughEdge(direction)) { if (roadEdges[direction]) { interpolators.x = interpolators.y = 0.5f; } else { interpolators.x = // hex.HasRoadThroughEdge(direction.Previous()) ? // 0.5f : 0.25f; roadEdges[direction.PreviousClockwise()] ? 0.5f : 0.25f; interpolators.y = // hex.HasRoadThroughEdge(direction.Next()) ? // 0.5f : 0.25f; roadEdges[direction.NextClockwise()] ? 0.5f : 0.25f; } return(interpolators); }
public HexEdge GetHexDirectionPreviousEdge( Hex hex, HexDirections direction ) { List <HexEdge> edges = GetOutEdgesList(hex); if (edges != null && edges.Count > 0) { foreach (HexEdge currentEdge in edges) { if (currentEdge.Direction == direction.PreviousClockwise()) { return(currentEdge); } } } return(null); }
private TerrainTriangulationData TriangulateTerrainAdjacentToRiver( Hex source, HexDirections direction, TerrainTriangulationData triangulationData, Dictionary <HexDirections, bool> roadEdges, HexRiverData riverData, float hexOuterRadius, int wrapSize, MapMeshChunkLayer terrain, FeatureContainer features ) { if (riverData.HasRiverInDirection(direction.NextClockwise())) { /* If the direction has a river on either side, it has a slight curve. * The center vertex of river-adjacent triangle needs to be moved toward * the edge so they don't overlap the river. */ // if (hex.HasRiverThroughEdge(direction.Previous())) { if ( riverData.HasRiverInDirection(direction.PreviousClockwise()) ) { triangulationData.terrainCenter += HexagonPoint.GetSolidEdgeMiddle( direction, hexOuterRadius ) * (HexagonConstants.INNER_TO_OUTER_RATIO * 0.5f); } /* If the hex has a river through the previous previous direction, * it has a river flowing through the hex. Move the center vertex * of the river-adjacent triangle so that it does not overlap the river. */ else if ( riverData.HasRiverInDirection( direction.PreviousClockwise2() ) ) { triangulationData.terrainCenter += HexagonPoint.GetFirstSolidCorner( direction, hexOuterRadius ) * 0.25f; } } /* Second case of straight-river-adjacent triangle. Need to move center * so it doesn't overlap the river. */ else if ( riverData.HasRiverInDirection(direction.PreviousClockwise()) && riverData.HasRiverInDirection(direction.NextClockwise2()) ) { triangulationData.terrainCenter += HexagonPoint.GetSecondSolidCorner( direction, hexOuterRadius ) * 0.25f; } EdgeVertices middle = new EdgeVertices( Vector3.Lerp( triangulationData.terrainCenter, triangulationData.centerEdgeVertices.vertex1, 0.5f ), Vector3.Lerp( triangulationData.terrainCenter, triangulationData.centerEdgeVertices.vertex5, 0.5f ) ); TriangulateEdgeStripTerrain( middle, _weights1, source.Index, triangulationData.centerEdgeVertices, _weights1, source.Index, hexOuterRadius, wrapSize, terrain ); TriangulateEdgeFan( triangulationData.terrainCenter, middle, source.Index, hexOuterRadius, wrapSize, terrain ); if (!source.IsUnderwater && roadEdges[direction]) { features.AddFeature( source, ( triangulationData.terrainCenter + triangulationData.centerEdgeVertices.vertex1 + triangulationData.centerEdgeVertices.vertex5 ) * (1f / 3f), hexOuterRadius, wrapSize ); } return(triangulationData); }
private TerrainTriangulationData TriangulateRiverBanks( TerrainTriangulationData data, HexRiverData riverData, HexDirections direction, float hexOuterRadius ) { if (riverData.HasRiverInDirection(direction.Opposite())) { /* Create a vertex 1/4th of the way from the center of the hex * to first solid corner of the previous edge, which is pointing * straight "down" toward the bottom of the hexagon for a left facing * edge. */ data.riverCenterLeft = data.terrainCenter + HexagonPoint.GetFirstSolidCorner( direction.PreviousClockwise(), hexOuterRadius ) * 0.25f; /* Create a vertex 1/4th of the way from the center of the hex * to the second solid corner of the next edge, which is pointing * straight "up" toward the top of the hexagon for a left facing edge. */ data.riverCenterRight = data.terrainCenter + HexagonPoint.GetSecondSolidCorner( direction.NextClockwise(), hexOuterRadius ) * 0.25f; } /* If the next direction has a sharp turn, there will be a river through * direction.Next() or direction.Previous(). Must align center line with * center line with edge between this river and the adjacent river. * Interpolate with an increased step to account for the rotation * of the center line. */ else if ( riverData.HasRiverInDirection(direction.NextClockwise()) ) { data.riverCenterLeft = data.terrainCenter; data.riverCenterRight = Vector3.Lerp( data.terrainCenter, data.centerEdgeVertices.vertex5, 2f / 3f ); } else if ( riverData.HasRiverInDirection(direction.PreviousClockwise()) ) { data.riverCenterLeft = Vector3.Lerp( data.terrainCenter, data.centerEdgeVertices.vertex1, 2f / 3f ); data.riverCenterRight = data.terrainCenter; } /* If the hex has a river two directions next, or two directions * previous, there is a slight bend in the river. Need to push * the center line to the inside of the bend. Using * HexMetrics.innerToOuter to adjust for the fact that * the midpoint of a solid edge is closer to the center * of a hex than a solid edge corner. */ else if ( riverData.HasRiverInDirection(direction.NextClockwise2()) ) { data.riverCenterLeft = data.terrainCenter; data.riverCenterRight = data.terrainCenter + HexagonPoint.GetSolidEdgeMiddle( direction.NextClockwise(), hexOuterRadius ) * (0.5f * HexagonConstants.INNER_TO_OUTER_RATIO); } // Previous 2 else { data.riverCenterLeft = data.terrainCenter + HexagonPoint.GetSolidEdgeMiddle( direction.PreviousClockwise(), hexOuterRadius ) * (0.5f * HexagonConstants.INNER_TO_OUTER_RATIO); data.riverCenterRight = data.terrainCenter; } /* Get the final location of the center by averaging * centerLeft and centerRight. For a straight through * river this average is the same as the center * of the hex. For a bend this moves the center * appropriately. Otherwise, all points are the same * and the center also remains at the center of the hex. */ data.terrainCenter = Vector3.Lerp( data.riverCenterLeft, data.riverCenterRight, 0.5f ); /* Create the middle edge vertices using points halfway between * centerLeft/centerRight and the 1st and 5th vertices of the * hexagons edge vertices for the given direction. Must use an * alternate constructor for the middle edge vertices object * because the length of the edge is 3/4ths rather than 1. To * keep the 2nd and 4th vertex in line with the rivers edges, * must interpolate by 1/6th instead of 1/3rd. */ EdgeVertices middleEdgeVertices = new EdgeVertices( Vector3.Lerp( data.riverCenterLeft, data.centerEdgeVertices.vertex1, 0.5f ), Vector3.Lerp( data.riverCenterRight, data.centerEdgeVertices.vertex5, 0.5f ), 1f / 6f ); /* Adjust the height of middle of the middle edge, * as well as the height of the center of the hexagon, to * the height of the middle of the outer edge of the * hexagon. The given edge of the hexagon has already * been adjusted to the height of the river bed. */ middleEdgeVertices.vertex3.y = data.terrainCenter.y = data.centerEdgeVertices.vertex3.y; data.middleEdgeVertices = middleEdgeVertices; return(data); }
public bool HasRiverInPreviousDirection(HexDirections direction) { return (IncomingRivers[direction.PreviousClockwise()] || OutgoingRivers[direction.PreviousClockwise()]); }
private TerrainTriangulationData TriangulateRoadAdjacentToRiver( Hex source, HexDirections direction, TerrainTriangulationData data, HexRiverData riverData, Dictionary <HexDirections, bool> roadEdges, float hexOuterRadius, int wrapSize, MapMeshChunkLayer roads, FeatureContainer features ) { // bool hasRoadThroughEdge = hex.HasRoadThroughEdge(direction); bool hasRoadThroughEdge = roadEdges[direction]; // bool previousHasRiver = hex.HasRiverThroughEdge( // direction.Previous() // ); bool previousHasRiver = riverData.HasIncomingRiverInDirection( direction.PreviousClockwise() ); // bool nextHasRiver = hex.HasRiverThroughEdge(direction.Next()); bool nextHasRiver = riverData.HasIncomingRiverInDirection( direction.NextClockwise() ); Vector2 interpolators = GetRoadInterpolators( source, direction, roadEdges ); Vector3 roadCenter = data.terrainCenter; // if (hex.HasRiverBeginOrEnd) { if (riverData.HasRiverStartOrEnd) { roadCenter += HexagonPoint.GetSolidEdgeMiddle( // hex.RiverBeginOrEndDirection.Opposite(), riverData.RiverStartOrEndDirection.Opposite(), hexOuterRadius ) * (1f / 3f); } // else if(hex.IncomingRiver == hex.OutgoingRiver.Opposite()) { else if ( riverData.HasStraightRiver ) { Vector3 corner; // If the previous hex has a river, the corner the center will be // moved toward is equal to the current direction + 1. if (previousHasRiver) { if ( !hasRoadThroughEdge && // !hex.HasRoadThroughEdge(direction.Next()) !roadEdges[direction.NextClockwise()] ) { return(data); } corner = HexagonPoint.GetSecondSolidCorner( direction, hexOuterRadius ); } // If the previous hex does not have a river, the corner the center will // be moved toward is the same index as the current direction. else { if ( !hasRoadThroughEdge && // !hex.HasRoadThroughEdge(direction.Previous()) !roadEdges[direction.PreviousClockwise()] ) { return(data); } corner = HexagonPoint.GetFirstSolidCorner( direction, hexOuterRadius ); } /* Using the example of a river flowing from east to west or west to east, for all cases * this will result in the river being pushed either directly "up" north away from the * river or directly "down" south away from the river. */ roadCenter += corner * 0.5f; if ( // hex.IncomingRiver == direction.Next() && riverData.IncomingRivers[direction.NextClockwise()] && // hex.HasRoadThroughEdge(direction.Next2()) || roadEdges[direction.NextClockwise2()] || // hex.HasRoadThroughEdge(direction.Opposite()) roadEdges[direction.Opposite()] ) { features.AddBridge( roadCenter, data.terrainCenter - corner * 0.5f, hexOuterRadius, wrapSize ); } data.terrainCenter += corner * 0.25f; } // If the river has a zigzag, then the incoming river will be the on the // edge previous from the outgoing river or the incoming river will be on // the next edge of the outoing river. In the case of the former, the // index of the corner whose vector is pointing away from the river is the // index of the incoming river + 1. Otherwise it is the index of the // incoming river. In both cases, subtracting the road center by that // vector times 0.2f is sufficent to push the road center away from the // river. // else if (hex.IncomingRiver == hex.OutgoingRiver.Previous()) { else if (riverData.HasPreviousClockwiseCornerRiver) { roadCenter -= HexagonPoint.GetSecondCorner( // hex.IncomingRiver, riverData.AnyIncomingRiver, hexOuterRadius ) * 0.2f; } // else if (hex.IncomingRiver == hex.OutgoingRiver.Next()) { else if (riverData.HasNextClockwiseCornerRiver) { roadCenter -= HexagonPoint.GetFirstCorner( // hex.IncomingRiver, riverData.AnyIncomingRiver, hexOuterRadius ) * 0.2f; } // If there is a river on the previous and next edges, the river has a // slight bend. Need to pull the road center toward the current hex edge, // which will shorten the road back away from the river. else if (previousHasRiver && nextHasRiver) { if (!hasRoadThroughEdge) { return(data); } // Must account for difference in scale between corners and middles by // using HexMetrics.innerToOuter. Vector3 offset = HexagonPoint.GetSolidEdgeMiddle( direction, hexOuterRadius ) * HexagonConstants.INNER_TO_OUTER_RATIO; roadCenter += offset * 0.7f; data.terrainCenter += offset * 0.5f; } // The only remaining case is that the hex lies on the outside of a // curving river. In this case, there are three edges pointing away from // the river. The middle edge of these three edges must be obtained. // Then, the center of the road is pushed toward the middle of this edge. else { HexDirections middle; if (previousHasRiver) { // middle = direction.Next(); middle = direction.NextClockwise(); } else if (nextHasRiver) { // middle = direction.Previous(); middle = direction.PreviousClockwise(); } else { // middle = direction; middle = direction; } // If there is no road through any of the hexes on the outer side of the // river bend, then the road center need not move and should instead be // pruned. if ( // !hex.HasRoadThroughEdge(middle) && !roadEdges[middle] && // !hex.HasRoadThroughEdge(middle.Previous()) && !roadEdges[middle.PreviousClockwise()] && // !hex.HasRoadThroughEdge(middle.Next()) !roadEdges[middle.NextClockwise()] ) { return(data); } Vector3 offset = HexagonPoint.GetSolidEdgeMiddle( middle, hexOuterRadius ); roadCenter += offset * 0.25f; if ( direction == middle && // hex.HasRoadThroughEdge(direction.Opposite()) roadEdges[direction.Opposite()] ) { features.AddBridge( roadCenter, data.terrainCenter - offset * ( HexagonConstants.INNER_TO_OUTER_RATIO * 0.7f ), hexOuterRadius, wrapSize ); } } Vector3 middleLeft = Vector3.Lerp( roadCenter, data.centerEdgeVertices.vertex1, interpolators.x ); Vector3 middleRight = Vector3.Lerp( roadCenter, data.centerEdgeVertices.vertex5, interpolators.y ); TriangulateRoad( roadCenter, middleLeft, middleRight, data.centerEdgeVertices, hasRoadThroughEdge, source.Index, hexOuterRadius, wrapSize, roads ); if (previousHasRiver) { TriangulateRoadEdge( roadCenter, data.terrainCenter, middleLeft, source.Index, hexOuterRadius, wrapSize, roads ); } if (nextHasRiver) { TriangulateRoadEdge( roadCenter, middleRight, data.terrainCenter, source.Index, hexOuterRadius, wrapSize, roads ); } return(data); }
private void TriangulateWaterShore( Hex source, Hex target, Vector3 waterSourceRelativeHexIndices, HexDirections direction, Dictionary <HexDirections, Hex> neighbors, HexRiverData riverData, Vector3 center, float hexOuterRadius, int wrapSize, MapMeshChunkLayer waterShore, EdgeVertices edge1, EdgeVertices edge2, float hexInnerDiameter ) { // hex.HasRiverThroughEdge(direction) if (riverData.HasRiverInDirection(direction)) { TriangulateWaterShoreWithRiver( edge1, edge2, riverData.HasIncomingRiverInDirection(direction), waterSourceRelativeHexIndices, hexOuterRadius, wrapSize, waterShore ); } else { waterShore.AddQuadPerturbed( edge1.vertex1, edge1.vertex2, edge2.vertex1, edge2.vertex2, hexOuterRadius, wrapSize ); waterShore.AddQuadPerturbed( edge1.vertex2, edge1.vertex3, edge2.vertex2, edge2.vertex3, hexOuterRadius, wrapSize ); waterShore.AddQuadPerturbed( edge1.vertex3, edge1.vertex4, edge2.vertex3, edge2.vertex4, hexOuterRadius, wrapSize ); waterShore.AddQuadPerturbed( edge1.vertex4, edge1.vertex5, edge2.vertex4, edge2.vertex5, hexOuterRadius, wrapSize ); 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.AddQuadHexData( waterSourceRelativeHexIndices, _weights1, _weights2 ); waterShore.AddQuadHexData( waterSourceRelativeHexIndices, _weights1, _weights2 ); waterShore.AddQuadHexData( waterSourceRelativeHexIndices, _weights1, _weights2 ); waterShore.AddQuadHexData( waterSourceRelativeHexIndices, _weights1, _weights2 ); } Hex nextNeighbor; // hex.GetNeighbor(direction.NextClockwise()); if ( neighbors.TryGetValue( direction.NextClockwise(), out nextNeighbor ) ) { Vector3 center3 = nextNeighbor.Position; if (nextNeighbor.ColumnIndex < source.ColumnIndex - 1) { center3.x += wrapSize * hexInnerDiameter; } else if (nextNeighbor.ColumnIndex > source.ColumnIndex + 1) { center3.x -= wrapSize * hexInnerDiameter; } // Work backward from the shore to obtain the triangle if the neighbor is // underwater, otherwise obtain normal triangle. Vector3 vertex3 = center3 + ( nextNeighbor.IsUnderwater ? HexagonPoint.GetFirstWaterCorner( direction.PreviousClockwise(), hexOuterRadius ) : HexagonPoint.GetFirstSolidCorner( direction.PreviousClockwise(), hexOuterRadius ) ); vertex3.y = center.y; waterShore.AddTrianglePerturbed( edge1.vertex5, edge2.vertex5, vertex3, hexOuterRadius, wrapSize ); waterSourceRelativeHexIndices.z = nextNeighbor.Index; waterShore.AddTriangleHexData( waterSourceRelativeHexIndices, _weights1, _weights2, _weights3 ); waterShore.AddTriangleUV( new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, nextNeighbor.IsUnderwater ? 0f : 1f) ); } }