public TerrainTriangulationData TriangulateHexTerrainEdge( Hex hex, Hex neighbor, TerrainTriangulationData triangulationData, Dictionary <HexDirections, Hex> neighbors, HexDirections direction, HexRiverData riverData, FeatureContainer features, Dictionary <HexDirections, bool> roadEdges, Dictionary <HexDirections, ElevationEdgeTypes> elevationEdgeTypes, float hexOuterRadius, int wrapSize ) { triangulationData = TriangulateTerrainCenter( riverData, direction, hex, triangulationData, hexOuterRadius, wrapSize, this, features, roadEdges ); if (direction <= HexDirections.Southeast) { triangulationData = TriangulateTerrainConnection( hex, neighbor, triangulationData, direction, riverData, roadEdges, elevationEdgeTypes, hexOuterRadius, wrapSize, this, features ); // Adjust the other edge of the connection if there is a river through // that edge. triangulationData = TryTriangulateNeighborTerrainCorner( hex, neighbor, triangulationData, direction, neighbors, hexOuterRadius, wrapSize, this, features ); } return(triangulationData); }
public WaterTriangulationData TriangulateHexWaterShoreEdge( Hex source, Hex neighbor, Dictionary <HexDirections, Hex> neighbors, HexDirections direction, HexRiverData riverData, WaterTriangulationData triangulationData, float hexOuterRadius, int wrapSize ) { if (source.IsUnderwater) { if ( !neighbor.IsUnderwater ) { Vector3 center2 = neighbor.Position; float hexInnerRadius = HexagonPoint.OuterToInnerRadius(hexOuterRadius); float hexInnerDiameter = hexInnerRadius * 2f; // / | y // / | // | | //source x/z | | target // | | // \ | // \ | y Vector3 waterShoreHexIndices; waterShoreHexIndices.x = waterShoreHexIndices.z = source.Index; waterShoreHexIndices.y = neighbor.Index; TriangulateWaterShore( source, neighbor, waterShoreHexIndices, direction, neighbors, riverData, triangulationData.waterSurfaceCenter, hexOuterRadius, wrapSize, this, triangulationData.sourceWaterEdge, triangulationData.neighborWaterEdge, hexInnerDiameter ); } } return(triangulationData); }
private TerrainTriangulationData TriangulateTerrainConnectionRoads( Hex source, Hex neighbor, TerrainTriangulationData data, HexDirections direction, HexRiverData riverData, Dictionary <HexDirections, bool> roadEdges, Dictionary <HexDirections, ElevationEdgeTypes> elevationEdgeTypes, float hexOuterRadius, int wrapSize, MapMeshChunkLayer roads ) { bool hasRoad = roadEdges[direction]; if ( // hex.GetEdgeType(direction) == ElevationEdgeTypes.Slope elevationEdgeTypes[direction] == ElevationEdgeTypes.Slope ) { if (hasRoad) { TriangulateEdgeTerracesRoads( data.centerEdgeVertices, source, data.connectionEdgeVertices, neighbor, hasRoad, hexOuterRadius, wrapSize, roads ); } } else { if (hasRoad) { TriangulateEdgeStripRoads( data.centerEdgeVertices, _weights1, source.Index, data.connectionEdgeVertices, _weights2, neighbor.Index, hexOuterRadius, wrapSize, roads ); } } return(data); }
public TerrainTriangulationData TriangulateHexRiverEdge( Hex hex, Hex neighbor, HexDirections direction, Dictionary <HexDirections, bool> roadEdges, HexRiverData riverData, TerrainTriangulationData triangulationData, float hexOuterRadius, int wrapSize ) { if (riverData.HasRiver) { triangulationData = TriangulateCenterRiverSurface( riverData, direction, hex, triangulationData, hexOuterRadius, wrapSize, this, roadEdges ); if (direction <= HexDirections.Southeast) { /*triangulationData = * GetConnectionEdgeVertices( * hex, * neighbor, * direction, * triangulationData, * hexOuterRadius * );*/ // Adjust the other edge of the connection if there is a river through // that edge. triangulationData = TriangulateRiverConnection( hex, neighbor, triangulationData, direction, riverData, hexOuterRadius, wrapSize, this ); } } return(triangulationData); }
private TerrainTriangulationData TriangulateCenterRiverQuads( Hex source, TerrainTriangulationData triangulationData, HexDirections direction, HexRiverData riverData, float hexOuterRadius, int wrapSize, MapMeshChunkLayer rivers ) { bool reversed = riverData.HasIncomingRiverInDirection( direction ); Vector3 centerHexIndices; centerHexIndices.x = centerHexIndices.y = centerHexIndices.z = source.Index; TriangulateRiverQuad( triangulationData.riverCenterLeft, triangulationData.riverCenterRight, triangulationData.middleEdgeVertices.vertex2, triangulationData.middleEdgeVertices.vertex4, source.RiverSurfaceY, 0.4f, reversed, centerHexIndices, hexOuterRadius, wrapSize, rivers ); TriangulateRiverQuad( triangulationData.middleEdgeVertices.vertex2, triangulationData.middleEdgeVertices.vertex4, triangulationData.centerEdgeVertices.vertex2, triangulationData.centerEdgeVertices.vertex4, source.RiverSurfaceY, 0.6f, reversed, centerHexIndices, hexOuterRadius, wrapSize, rivers ); return(triangulationData); }
private TerrainTriangulationData TriangulateCenterRiverSurface( HexRiverData riverData, HexDirections direction, Hex source, TerrainTriangulationData data, float hexOuterRadius, int wrapSize, MapMeshChunkLayer rivers, Dictionary <HexDirections, bool> roadEdges ) { if (riverData.HasRiver) { if (riverData.HasRiverInDirection(direction)) { // If the triangle has a river through the edge, lower center edge vertex // to simulate stream bed. if (riverData.HasRiverStartOrEnd) { if (!source.IsUnderwater) { data = TriangulateRiverBeginOrEndRiver( source, data, riverData, hexOuterRadius, wrapSize, rivers ); } } else if (!source.IsUnderwater) { data = TriangulateCenterRiverQuads( source, data, direction, riverData, hexOuterRadius, wrapSize, rivers ); } } } return(data); }
public WaterTriangulationData TriangulateHexEstuaryEdge( Hex source, Hex neighbor, HexDirections direction, HexRiverData riverData, WaterTriangulationData triangulationData, float hexOuterRadius, int wrapSize ) { if (source.IsUnderwater) { if (!neighbor.IsUnderwater) { if (riverData.HasRiverInDirection(direction)) { // / | y // / | // | | //source x/z | | target // | | // \ | // \ | y Vector3 waterShoreHexIndices; waterShoreHexIndices.x = waterShoreHexIndices.z = source.Index; waterShoreHexIndices.y = neighbor.Index; TriangulateEstuary( triangulationData.sourceWaterEdge, triangulationData.neighborWaterEdge, riverData.HasIncomingRiverInDirection(direction), waterShoreHexIndices, hexOuterRadius, wrapSize, this ); } } } return(triangulationData); }
public TerrainTriangulationData TriangulateHexRoadEdge( Hex hex, Hex neighbor, TerrainTriangulationData triangulationData, HexDirections direction, HexRiverData riverData, FeatureContainer features, Dictionary <HexDirections, bool> roadEdges, Dictionary <HexDirections, ElevationEdgeTypes> elevationEdgeTypes, float hexOuterRadius, int wrapSize ) { triangulationData = TriangulateCenterRiverRoad( riverData, direction, hex, triangulationData, hexOuterRadius, wrapSize, this, roadEdges, features ); if (direction <= HexDirections.Southeast) { triangulationData = TriangulateTerrainConnectionRoads( hex, neighbor, triangulationData, direction, riverData, roadEdges, elevationEdgeTypes, hexOuterRadius, wrapSize, this ); } return(triangulationData); }
/// <summary> /// Triangulate the mesh geometry of an individual hex. /// </summary> /// <param name="source"> /// The hex to whose mesh geometry is to be triangluated. /// </param> /// <param name="hexOuterRadius"> /// The outer radius of the hex to be triangulated. /// </param> /// <param name="adjacencyGraph"> /// /// </param> /// <param name="riverDigraph"></param> /// <param name="roadUndirectedGraph"></param> /// <param name="elevationDigraph"></param> /// <param name="wrapSize"></param> private void TriangulateHex( Hex source, Dictionary <HexDirections, Hex> neighbors, List <HexDirections> borderDirections, float hexOuterRadius, HexRiverData riverData, Dictionary <HexDirections, bool> roadEdges, Dictionary <HexDirections, ElevationEdgeTypes> elevationEdgeTypes, int wrapSize, TerrainChunkLayer terrainLayer, RiversChunkLayer riversLayer, RoadsChunkLayer roadsLayer, OpenWaterChunkLayer openWaterLayer, WaterShoreChunkLayer waterShoreLayer, EstuariesChunkLayer estuariesLayer, FeatureContainer features ) { foreach ( KeyValuePair <HexDirections, Hex> pair in neighbors ) { // Initialize triangulation data. HexDirections direction = pair.Key; Hex neighbor = pair.Value; TerrainTriangulationData terrainTriData = new TerrainTriangulationData(); terrainTriData.terrainCenter = source.Position; terrainTriData = GetCenterEdgeVertices( direction, terrainTriData, hexOuterRadius ); if (direction <= HexDirections.Southeast) { terrainTriData = GetConnectionEdgeVertices( source, neighbor, direction, terrainTriData, hexOuterRadius ); } // Triangulate layers for non-border edge. terrainTriData = terrainLayer.TriangulateHexTerrainEdge( source, neighbor, terrainTriData, neighbors, direction, riverData, features, roadEdges, elevationEdgeTypes, hexOuterRadius, wrapSize ); terrainTriData = roadsLayer.TriangulateHexRoadEdge( source, neighbor, terrainTriData, direction, riverData, features, roadEdges, elevationEdgeTypes, hexOuterRadius, wrapSize ); terrainTriData = riversLayer.TriangulateHexRiverEdge( source, neighbor, direction, roadEdges, riverData, terrainTriData, hexOuterRadius, wrapSize ); WaterTriangulationData waterTriData = new WaterTriangulationData(); waterTriData = GetWaterData( source, neighbor, waterTriData, direction, hexOuterRadius, wrapSize ); waterTriData = openWaterLayer.TriangulateHexOpenWaterEdge( source, neighbor, neighbors, direction, waterTriData, terrainTriData, hexOuterRadius, wrapSize ); waterTriData = waterShoreLayer.TriangulateHexWaterShoreEdge( source, neighbor, neighbors, direction, riverData, waterTriData, hexOuterRadius, wrapSize ); waterTriData = estuariesLayer.TriangulateHexEstuaryEdge( source, neighbor, direction, riverData, waterTriData, hexOuterRadius, wrapSize ); } bool anyEdge = false; foreach (KeyValuePair <HexDirections, bool> pair in roadEdges) { if (pair.Value) { anyEdge = true; break; } } // Add feature or special to hex. if (!source.IsUnderwater) { if ( !riverData.HasRiver && !anyEdge ) { features.AddFeature( source, source.Position, hexOuterRadius, wrapSize ); } if (source.IsSpecial) { features.AddSpecialFeature( source, source.Position, hexOuterRadius, wrapSize ); } } }
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); }
private TerrainTriangulationData TriangulateTerrainConnection( Hex source, Hex neighbor, TerrainTriangulationData data, HexDirections direction, HexRiverData riverData, Dictionary <HexDirections, bool> roadEdges, Dictionary <HexDirections, ElevationEdgeTypes> elevationEdgeTypes, float hexOuterRadius, int wrapSize, MapMeshChunkLayer terrain, FeatureContainer features ) { if (riverData.HasRiverInDirection(direction)) { data.connectionEdgeVertices.vertex3.y = neighbor.StreamBedY; } bool hasRoad = roadEdges[direction]; if ( // hex.GetEdgeType(direction) == ElevationEdgeTypes.Slope elevationEdgeTypes[direction] == ElevationEdgeTypes.Slope ) { TriangulateEdgeTerracesTerrain( data.centerEdgeVertices, source, data.connectionEdgeVertices, neighbor, hexOuterRadius, wrapSize, terrain ); } else { TriangulateEdgeStripTerrain( data.centerEdgeVertices, _weights1, source.Index, data.connectionEdgeVertices, _weights2, neighbor.Index, hexOuterRadius, wrapSize, terrain ); } features.AddWall( data.centerEdgeVertices, source, data.connectionEdgeVertices, neighbor, riverData.HasRiverInDirection(direction), hasRoad, hexOuterRadius, wrapSize ); return(data); }
private TerrainTriangulationData TriangulateRiverConnection( Hex source, Hex neighbor, TerrainTriangulationData data, HexDirections direction, HexRiverData riverData, float hexOuterRadius, int wrapSize, MapMeshChunkLayer rivers ) { if (riverData.HasRiverInDirection(direction)) { Vector3 indices; indices.x = indices.z = source.Index; indices.y = neighbor.Index; if (!source.IsUnderwater) { if (!neighbor.IsUnderwater) { TriangulateRiverQuad( data.centerEdgeVertices.vertex2, data.centerEdgeVertices.vertex4, data.connectionEdgeVertices.vertex2, data.connectionEdgeVertices.vertex4, source.RiverSurfaceY, neighbor.RiverSurfaceY, 0.8f, ( // hex.HasIncomingRiver && // hex.IncomingRiver == direction riverData.HasIncomingRiverInDirection( direction ) ), indices, hexOuterRadius, wrapSize, rivers ); } else if (source.elevation > neighbor.WaterLevel) { TriangulateWaterfallInWater( data.centerEdgeVertices.vertex2, data.centerEdgeVertices.vertex4, data.connectionEdgeVertices.vertex2, data.connectionEdgeVertices.vertex4, source.RiverSurfaceY, neighbor.RiverSurfaceY, neighbor.WaterSurfaceY, indices, hexOuterRadius, wrapSize, rivers ); } } else if ( !neighbor.IsUnderwater && neighbor.elevation > source.WaterLevel ) { TriangulateWaterfallInWater( data.connectionEdgeVertices.vertex4, data.connectionEdgeVertices.vertex2, data.centerEdgeVertices.vertex4, data.centerEdgeVertices.vertex2, neighbor.RiverSurfaceY, source.RiverSurfaceY, source.WaterSurfaceY, indices, hexOuterRadius, wrapSize, rivers ); } } 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) ); } }
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); }
public void Triangulate( HexMap hexMap, float hexOuterRadius, HexAdjacencyGraph adjacencyGraph, RiverDigraph riverGraph, RoadUndirectedGraph roadGraph, ElevationDigraph elevationGraph ) { _terrainLayer.Clear(); _riversLayer.Clear(); _roadsLayer.Clear(); _openWaterLayer.Clear(); _waterShoreLayer.Clear(); _estuariesLayer.Clear(); _features.Clear(); for (int i = 0; i < Hexes.Length; i++) { Hex current = Hexes[i]; if (current) { Dictionary <HexDirections, Hex> neighbors = adjacencyGraph.GetNeighborByDirection(current); Dictionary <HexDirections, ElevationEdgeTypes> edgeTypes = elevationGraph.GetNeighborEdgeTypes(current); Dictionary <HexDirections, bool> roadEdges = roadGraph.GetNeighborRoads(current); List <HexDirections> borderDirections = adjacencyGraph.GetBorderDirectionsList(current); HexRiverData riverData = riverGraph.GetRiverData(current); TriangulateHex( current, neighbors, borderDirections, hexOuterRadius, riverData, roadEdges, edgeTypes, hexMap.WrapSize, _terrainLayer, _riversLayer, _roadsLayer, _openWaterLayer, _waterShoreLayer, _estuariesLayer, _features ); } } _terrainLayer.Draw(); _riversLayer.Draw(); _roadsLayer.Draw(); _openWaterLayer.Draw(); _waterShoreLayer.Draw(); _estuariesLayer.Draw(); _features.Apply(); }
private TerrainTriangulationData TriangulateCenterRiverRoad( HexRiverData riverData, HexDirections direction, Hex source, TerrainTriangulationData data, float hexOuterRadius, int wrapSize, MapMeshChunkLayer roads, Dictionary <HexDirections, bool> roadEdges, FeatureContainer features ) { if (riverData.HasRiver) { bool hasRoad = false; foreach ( KeyValuePair <HexDirections, bool> pair in roadEdges ) { if (pair.Value) { hasRoad = true; break; } } if (hasRoad) { TriangulateRoadAdjacentToRiver( source, direction, data, riverData, roadEdges, hexOuterRadius, wrapSize, roads, features ); } } else { bool anyRoad = false; foreach ( KeyValuePair <HexDirections, bool> pair in roadEdges ) { if (pair.Value) { anyRoad = true; break; } } if (anyRoad) { TriangulateRoadWithoutRiver( source, direction, data.centerEdgeVertices, roadEdges, data.terrainCenter, hexOuterRadius, wrapSize, roads ); } } return(data); }
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 TerrainTriangulationData TriangulateTerrainCenter( HexRiverData riverData, HexDirections direction, Hex source, TerrainTriangulationData data, float hexOuterRadius, int wrapSize, MapMeshChunkLayer terrain, FeatureContainer features, Dictionary <HexDirections, bool> roadEdges ) { if (riverData.HasRiver) { if (riverData.HasRiverInDirection(direction)) { data.centerEdgeVertices.vertex3.y = source.StreamBedY; if (riverData.HasRiverStartOrEnd) { data = TriangulateRiverBeginOrEndTerrain( source, data, hexOuterRadius, wrapSize, terrain ); } else { data = TriangulateRiverBanks( data, riverData, direction, hexOuterRadius ); data = TriangulateRiverTerrain( source, data, hexOuterRadius, wrapSize, terrain ); } } else { data = TriangulateTerrainAdjacentToRiver( source, direction, data, roadEdges, riverData, hexOuterRadius, wrapSize, terrain, features ); } } else { // Triangulate terrain center without river, basic edge fan. TriangulateEdgeFan( data.terrainCenter, data.centerEdgeVertices, source.Index, hexOuterRadius, wrapSize, terrain ); if ( !source.IsUnderwater && !roadEdges[direction] ) { features.AddFeature( source, ( data.terrainCenter + data.centerEdgeVertices.vertex1 + data.centerEdgeVertices.vertex5 ) * (1f / 3f), hexOuterRadius, wrapSize ); } } return(data); }
private TerrainTriangulationData TriangulateRiverBeginOrEndRiver( Hex source, TerrainTriangulationData triangulationData, HexRiverData riverData, float hexOuterRadius, int wrapSize, MapMeshChunkLayer rivers ) { Vector3 riverSurfaceCenter = triangulationData.terrainCenter; // bool reversed = hex.HasIncomingRiver; bool reversed = riverData.HasIncomingRiver; Vector3 indices = new Vector3( source.Index, source.Index, source.Index ); TriangulateRiverQuad( triangulationData.middleEdgeVertices.vertex2, triangulationData.middleEdgeVertices.vertex4, triangulationData.centerEdgeVertices.vertex2, triangulationData.centerEdgeVertices.vertex4, source.RiverSurfaceY, 0.6f, reversed, indices, hexOuterRadius, wrapSize, rivers ); riverSurfaceCenter.y = triangulationData.middleEdgeVertices.vertex2.y = triangulationData.middleEdgeVertices.vertex4.y = source.RiverSurfaceY; rivers.AddTrianglePerturbed( riverSurfaceCenter, triangulationData.middleEdgeVertices.vertex2, triangulationData.middleEdgeVertices.vertex4, hexOuterRadius, wrapSize ); if (reversed) { rivers.AddTriangleUV( new Vector2(0.5f, 0.4f), new Vector2(1f, 0.2f), new Vector2(0f, 0.2f) ); } else { rivers.AddTriangleUV( new Vector2(0.5f, 0.4f), new Vector2(0f, 0.6f), new Vector2(1f, 0.6f) ); } rivers.AddTriangleHexData(indices, _weights1); return(triangulationData); }