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 TriangulateHexOpenWaterEdge( Hex source, Hex neighbor, Dictionary <HexDirections, Hex> neighbors, HexDirections direction, WaterTriangulationData waterTriData, TerrainTriangulationData terrainTriData, float hexOuterRadius, int wrapSize ) { if (source.IsUnderwater) { if ( !neighbor.IsUnderwater ) { waterTriData = TriangulateShoreOpenWater( source, neighbor, waterTriData.waterSurfaceCenter, waterTriData.sourceWaterEdge, hexOuterRadius, wrapSize, this, waterTriData ); } else { waterTriData = TriangulateOpenWaterCenter( source, waterTriData, direction, hexOuterRadius, wrapSize, this ); waterTriData = TriangulateOpenWaterConnection( source, neighbor, direction, waterTriData, terrainTriData, neighbors, hexOuterRadius, wrapSize, this ); } } return(waterTriData); }
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); }
private TerrainTriangulationData TriangulateRiverBeginOrEndTerrain( Hex source, TerrainTriangulationData data, float hexOuterRadius, int wrapSize, MapMeshChunkLayer terrain ) { data.middleEdgeVertices = new EdgeVertices( Vector3.Lerp( data.terrainCenter, data.centerEdgeVertices.vertex1, 0.5f ), Vector3.Lerp( data.terrainCenter, data.centerEdgeVertices.vertex5, 0.5f ) ); data.middleEdgeVertices.vertex3.y = source.StreamBedY; TriangulateEdgeStripTerrain( data.middleEdgeVertices, _weights1, source.Index, data.centerEdgeVertices, _weights1, source.Index, hexOuterRadius, wrapSize, terrain ); TriangulateEdgeFan( data.terrainCenter, data.middleEdgeVertices, source.Index, hexOuterRadius, wrapSize, terrain ); return(data); }
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); }
protected TerrainTriangulationData GetCenterEdgeVertices( HexDirections direction, TerrainTriangulationData data, float hexOuterRadius ) { // Triangle edge. data.centerEdgeVertices = new EdgeVertices( data.terrainCenter + HexagonPoint.GetFirstSolidCorner( direction, hexOuterRadius ), data.terrainCenter + HexagonPoint.GetSecondSolidCorner( direction, hexOuterRadius ) ); return(data); }
protected TerrainTriangulationData GetConnectionEdgeVertices( Hex source, Hex neighbor, HexDirections direction, TerrainTriangulationData data, float hexOuterRadius ) { Vector3 bridge = HexagonPoint.GetBridge( direction, hexOuterRadius ); bridge.y = neighbor.Position.y - source.Position.y; data.connectionEdgeVertices = new EdgeVertices( data.centerEdgeVertices.vertex1 + bridge, data.centerEdgeVertices.vertex5 + bridge ); return(data); }
private TerrainTriangulationData TryTriangulateNeighborTerrainCorner( Hex source, Hex neighbor, TerrainTriangulationData data, HexDirections direction, Dictionary <HexDirections, Hex> neighbors, float hexOuterRadius, int wrapSize, MapMeshChunkLayer terrain, FeatureContainer features ) { Hex nextNeighbor; if ( neighbors.TryGetValue( direction.NextClockwise(), out nextNeighbor ) && direction <= HexDirections.East ) { TriangulateNeighborTerrainCorner( source, neighbor, nextNeighbor, direction, data, hexOuterRadius, wrapSize, terrain, features ); } 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 TriangulateNeighborTerrainCorner( Hex source, Hex neighbor, Hex nextNeighbor, HexDirections direction, TerrainTriangulationData data, float hexOuterRadius, int wrapSize, MapMeshChunkLayer terrain, FeatureContainer features ) { // Create a 5th vertex and assign it with the elevation of the neighbor // under consideration. This will be used as the final vertex in the // triangle which fills the gap between bridges. Vector3 vertex5 = data.centerEdgeVertices.vertex5 + HexagonPoint.GetBridge( direction.NextClockwise(), hexOuterRadius ); vertex5.y = nextNeighbor.Position.y; if (source.elevation <= neighbor.elevation) { if (source.elevation <= nextNeighbor.elevation) { // This hex has lowest elevation, no rotation. TriangulateTerrainCorner( data.centerEdgeVertices.vertex5, source, data.connectionEdgeVertices.vertex5, neighbor, vertex5, nextNeighbor, hexOuterRadius, wrapSize, terrain, features ); } else { // Next neighbor has lowest elevation, rotate counter-clockwise. TriangulateTerrainCorner( vertex5, nextNeighbor, data.centerEdgeVertices.vertex5, source, data.connectionEdgeVertices.vertex5, neighbor, hexOuterRadius, wrapSize, terrain, features ); } } else if (neighbor.elevation <= nextNeighbor.elevation) { // Neighbor is lowest hex, rotate triangle clockwise. TriangulateTerrainCorner( data.connectionEdgeVertices.vertex5, neighbor, vertex5, nextNeighbor, data.centerEdgeVertices.vertex5, source, hexOuterRadius, wrapSize, terrain, features ); } else { // Next neighbor has lowest elevation, rotate counter-clockwise. TriangulateTerrainCorner( vertex5, nextNeighbor, data.centerEdgeVertices.vertex5, source, data.connectionEdgeVertices.vertex5, neighbor, hexOuterRadius, wrapSize, terrain, features ); } return(data); }
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 TriangulateRiverTerrain( Hex source, TerrainTriangulationData triangulationData, float hexOuterRadius, int wrapSize, MapMeshChunkLayer terrain ) { TriangulateEdgeStripTerrain( triangulationData.middleEdgeVertices, _weights1, source.Index, triangulationData.centerEdgeVertices, _weights1, source.Index, hexOuterRadius, wrapSize, terrain ); terrain.AddTrianglePerturbed( triangulationData.riverCenterLeft, triangulationData.middleEdgeVertices.vertex1, triangulationData.middleEdgeVertices.vertex2, hexOuterRadius, wrapSize ); terrain.AddQuadPerturbed( triangulationData.riverCenterLeft, triangulationData.terrainCenter, triangulationData.middleEdgeVertices.vertex2, triangulationData.middleEdgeVertices.vertex3, hexOuterRadius, wrapSize ); terrain.AddQuadPerturbed( triangulationData.terrainCenter, triangulationData.riverCenterRight, triangulationData.middleEdgeVertices.vertex3, triangulationData.middleEdgeVertices.vertex4, hexOuterRadius, wrapSize ); terrain.AddTrianglePerturbed( triangulationData.riverCenterRight, triangulationData.middleEdgeVertices.vertex4, triangulationData.middleEdgeVertices.vertex5, hexOuterRadius, wrapSize ); Vector3 centerHexIndices; centerHexIndices.x = centerHexIndices.y = centerHexIndices.z = source.Index; terrain.AddTriangleHexData( centerHexIndices, _weights1 ); terrain.AddQuadHexData( centerHexIndices, _weights1 ); terrain.AddQuadHexData( centerHexIndices, _weights1 ); terrain.AddTriangleHexData( centerHexIndices, _weights1 ); return(triangulationData); }
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 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 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); }
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 WaterTriangulationData TriangulateOpenWaterConnection( Hex source, Hex target, HexDirections direction, WaterTriangulationData waterTriData, TerrainTriangulationData terrainTriData, Dictionary <HexDirections, Hex> neighbors, float hexOuterRadius, int wrapSize, MapMeshChunkLayer water ) { if ( direction <= HexDirections.Southeast ) { Vector3 bridge = HexagonPoint.GetWaterBridge( direction, hexOuterRadius ); Vector3 edge1 = waterTriData.waterSurfaceCornerLeft + bridge; Vector3 edge2 = waterTriData.waterSurfaceCornerRight + bridge; water.AddQuadPerturbed( waterTriData.waterSurfaceCornerLeft, waterTriData.waterSurfaceCornerRight, edge1, edge2, hexOuterRadius, wrapSize ); Vector3 openWaterIndices; openWaterIndices.x = openWaterIndices.z = source.Index; openWaterIndices.y = target.Index; water.AddQuadHexData( openWaterIndices, _weights1, _weights2 ); if (direction <= HexDirections.East) { Hex nextNeighbor; if ( neighbors.TryGetValue( direction.NextClockwise(), out nextNeighbor ) && nextNeighbor.IsUnderwater ) { water.AddTrianglePerturbed( waterTriData.waterSurfaceCornerRight, edge2, waterTriData.waterSurfaceCornerRight + HexagonPoint.GetWaterBridge( direction.NextClockwise(), hexOuterRadius ), hexOuterRadius, wrapSize ); openWaterIndices.z = nextNeighbor.Index; water.AddTriangleHexData( openWaterIndices, _weights1, _weights2, _weights3 ); } } } return(waterTriData); }
/// <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 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); }