public void BuildNonRiverContour(IHexCell center, HexDirection direction) { if (RiverCanon.HasRiverAlongEdge(center, direction)) { return; } var contourPoints = new List <Vector2>(); IHexCell left = Grid.GetNeighbor(center, direction.Previous()); IHexCell right = Grid.GetNeighbor(center, direction); IHexCell nextRight = Grid.GetNeighbor(center, direction.Next()); bool hasCenterLeftRiver = RiverCanon.HasRiverAlongEdge(center, direction.Previous()); bool hasCenterNextRightRiver = RiverCanon.HasRiverAlongEdge(center, direction.Next()); bool hasLeftRightRiver = left != null && RiverCanon.HasRiverAlongEdge(left, direction.Next()); bool hasNextRightRightRiver = nextRight != null && RiverCanon.HasRiverAlongEdge(nextRight, direction.Previous()); if (hasCenterLeftRiver) { ICollection <Vector2> centerLeftContour = CellEdgeContourCanon.GetContourForCellEdge(center, direction.Previous()); contourPoints.Add(centerLeftContour.Last()); } else if (hasLeftRightRiver) { ICollection <Vector2> rightLeftContour = CellEdgeContourCanon.GetContourForCellEdge(right, direction.Previous2()); contourPoints.Add(rightLeftContour.First()); } else { contourPoints.Add(center.AbsolutePositionXZ + RenderConfig.GetFirstCornerXZ(direction)); } if (hasCenterNextRightRiver || (hasNextRightRightRiver && RiverCanon.GetFlowOfRiverAtEdge(nextRight, direction.Previous()) == RiverFlow.Clockwise) ) { ICollection <Vector2> centerNextRightContour = CellEdgeContourCanon.GetContourForCellEdge(center, direction.Next()); contourPoints.Add(centerNextRightContour.First()); } else if (hasNextRightRightRiver) { //We need to add two points here in case the edge is up against the //outflow of a river. We've decided to give the outflow over entirely //to one of the cells, but other constructions are possible. ICollection <Vector2> rightNextRightContour = CellEdgeContourCanon.GetContourForCellEdge(right, direction.Next2()); ICollection <Vector2> nextRightRightContour = CellEdgeContourCanon.GetContourForCellEdge(nextRight, direction.Previous()); contourPoints.Add(rightNextRightContour.Last()); contourPoints.Add(nextRightRightContour.First()); } else { contourPoints.Add(center.AbsolutePositionXZ + RenderConfig.GetSecondCornerXZ(direction)); } CellEdgeContourCanon.SetContourForCellEdge(center, direction, contourPoints); }
private void TriangulateRiver(RiverSpline riverSpline) { Vector3 riverYVector = Vector3.up * RenderConfig.WaterY; var centerSpline = riverSpline.CenterSpline; float maxSurfaceWidth = RenderConfig.RiverMaxSurfaceWidth * Mathf.Clamp01((float)centerSpline.CurveCount / RenderConfig.RiverCurvesForMaxWidth); float maxBankWidth = (RenderConfig.RiverMaxSurfaceWidth + RenderConfig.RiverMaxBankWidth) * Mathf.Clamp01((float)centerSpline.CurveCount / RenderConfig.RiverCurvesForMaxWidth); int riverQuadCount = centerSpline.CurveCount * RenderConfig.RiverQuadsPerCurve; float tDelta = 1f / riverQuadCount; float t = 0f; Vector3 surfacePortV1, surfaceStarboardV1, bankPortV1, bankStarboardV1, center1, duckPortV1, duckStarboardV1; Vector3 center2 = centerSpline.GetPoint(tDelta) + riverYVector; float noise = NoiseGenerator.SampleNoise( new Vector2(center2.x, center2.z), RenderConfig.GenericNoiseSource, RenderConfig.RiverWidthNoise, NoiseType.NegativeOneToOne ).x; Vector3 flow1 = centerSpline.GetDirection(t); Vector3 flow2 = centerSpline.GetDirection(tDelta); float surfaceWidth = maxSurfaceWidth * (Mathf.Clamp01(tDelta * RenderConfig.RiverWideningRate) + tDelta * noise); float bankWidth = maxBankWidth * (Mathf.Clamp01(tDelta * RenderConfig.RiverWideningRate) + tDelta * noise); Vector3 surfacePortV2 = center2 + centerSpline.GetNormalXZ(tDelta) * surfaceWidth; Vector3 surfaceStarboardV2 = center2 - centerSpline.GetNormalXZ(tDelta) * surfaceWidth; Vector3 bankPortV2 = center2 + centerSpline.GetNormalXZ(tDelta) * bankWidth; Vector3 bankStarboardV2 = center2 - centerSpline.GetNormalXZ(tDelta) * bankWidth; Grid.RiverSurfaceMesh.AddTriangle(centerSpline.Points[0] + riverYVector, surfacePortV2, surfaceStarboardV2); Grid.RiverSurfaceMesh.AddTriangleUV3(flow1, flow2, flow2); Grid.RiverSurfaceMesh.AddTriangleColor(RenderConfig.RiverWaterColor); Grid.RiverBankMesh.AddTriangle(centerSpline.Points[0] + riverYVector, bankPortV2, bankStarboardV2); Grid.RiverBankMesh.AddTriangleUV(Vector2.one, Vector2.zero, Vector2.zero); Vector3 duckPortV2, duckStarboardV2; BuildDuckStartCap( center2, centerSpline, bankPortV2, bankStarboardV2, tDelta, riverYVector, out duckPortV2, out duckStarboardV2 ); //Triangulating the main body of the river for (int sectionIndex = 0; sectionIndex < riverSpline.WesternCells.Count; sectionIndex++) { List <Vector2> thisEdgeContour = new List <Vector2>(); List <Vector2> neighborEdgeContour = new List <Vector2>(); if (sectionIndex == 0) { thisEdgeContour.Add(new Vector2(centerSpline.Points[0].x, centerSpline.Points[0].z)); neighborEdgeContour.Add(new Vector2(centerSpline.Points[0].x, centerSpline.Points[0].z)); } var sectionFlow = riverSpline.Flows[sectionIndex]; for (int pointIndex = 0; pointIndex < RenderConfig.RiverQuadsPerCurve; pointIndex++) { t += tDelta; surfacePortV1 = surfacePortV2; surfaceStarboardV1 = surfaceStarboardV2; bankPortV1 = bankPortV2; bankStarboardV1 = bankStarboardV2; duckPortV1 = duckPortV2; duckStarboardV1 = duckStarboardV2; center1 = center2; center2 = centerSpline.GetPoint(t) + riverYVector; noise = NoiseGenerator.SampleNoise( new Vector2(center2.x, center2.z), RenderConfig.GenericNoiseSource, RenderConfig.RiverWidthNoise, NoiseType.NegativeOneToOne ).x; surfaceWidth = maxSurfaceWidth * (Mathf.Clamp01(t * RenderConfig.RiverWideningRate) + t * noise); bankWidth = maxBankWidth * (Mathf.Clamp01(t * RenderConfig.RiverWideningRate) + t * noise); flow1 = flow2; flow2 = centerSpline.GetDirection(t); surfacePortV2 = center2 + centerSpline.GetNormalXZ(t) * surfaceWidth; surfaceStarboardV2 = center2 - centerSpline.GetNormalXZ(t) * surfaceWidth; bankPortV2 = center2 + centerSpline.GetNormalXZ(t) * bankWidth; bankStarboardV2 = center2 - centerSpline.GetNormalXZ(t) * bankWidth; duckPortV2 = center2 + centerSpline.GetNormalXZ(t) * RenderConfig.RiverDuckWidth; duckStarboardV2 = center2 - centerSpline.GetNormalXZ(t) * RenderConfig.RiverDuckWidth; Grid.RiverSurfaceMesh.AddQuad(surfacePortV1, surfaceStarboardV1, surfacePortV2, surfaceStarboardV2); Grid.RiverSurfaceMesh.AddQuadUV3(flow1, flow1, flow2, flow2); Grid.RiverSurfaceMesh.AddQuadColor(RenderConfig.RiverWaterColor); Grid.RiverBankMesh.AddQuad(center1, center2, bankPortV1, bankPortV2); Grid.RiverBankMesh.AddQuadUV(Vector2.one, Vector2.one, Vector2.zero, Vector2.zero); Grid.RiverBankMesh.AddQuad(center2, center1, bankStarboardV2, bankStarboardV1); Grid.RiverBankMesh.AddQuadUV(Vector2.one, Vector2.one, Vector2.zero, Vector2.zero); Grid.RiverDuckMesh.AddQuad(bankPortV1, bankPortV2, duckPortV1, duckPortV2); Grid.RiverDuckMesh.AddQuadUV(Vector2.one, Vector2.one, Vector2.zero, Vector2.zero); Grid.RiverDuckMesh.AddQuad(bankPortV2, bankPortV1, bankStarboardV2, bankStarboardV1); Grid.RiverDuckMesh.AddQuadUV(Vector2.one, Vector2.one, Vector2.one, Vector2.one); Grid.RiverDuckMesh.AddQuad(bankStarboardV2, bankStarboardV1, duckStarboardV2, duckStarboardV1); Grid.RiverDuckMesh.AddQuadUV(Vector2.one, Vector2.one, Vector2.zero, Vector2.zero); thisEdgeContour.Add(sectionFlow == RiverFlow.Counterclockwise ? surfacePortV1.ToXZ() : surfaceStarboardV1.ToXZ()); neighborEdgeContour.Add(sectionFlow == RiverFlow.Counterclockwise ? surfaceStarboardV1.ToXZ() : surfacePortV1.ToXZ()); } thisEdgeContour.Add(sectionFlow == RiverFlow.Counterclockwise ? surfacePortV2.ToXZ() : surfaceStarboardV2.ToXZ()); neighborEdgeContour.Add(sectionFlow == RiverFlow.Counterclockwise ? surfaceStarboardV2.ToXZ() : surfacePortV2.ToXZ()); CellEdgeContourCanon.SetContourForCellEdge( riverSpline.WesternCells[sectionIndex], riverSpline.Directions[sectionIndex], thisEdgeContour ); CellEdgeContourCanon.SetContourForCellEdge( riverSpline.EasternCells[sectionIndex], riverSpline.Directions[sectionIndex].Opposite(), neighborEdgeContour ); } BuildDuckEndCap(riverSpline, duckPortV2, duckStarboardV2, bankPortV2, bankStarboardV2); }
/* * There are a handful of possible cases for this method. * * In the first case, CenterLeftContour and CenterRightContour intersect each-other. * In that case, we want to remove all of the points in each contour beyond the other * and then join them at the intersect. We do this by checking the contours in opposite * directions. Because all contours are oriented clockwise around their cell, if we * check for line segment collision carefully we'll know exactly which points need to * be removed. Any intersection will appear close to the beginning of CenterRightContour * and the end of CenterLeftContour. Thus we work up CenterRightContour and down * CenterLeftContour. Once we find an intersection, we strip points from the beginning of * CenterRightContour and the end of CenterLeftContour and add the intersection point at * the beginning and end, respectively. * * In the second case, CenterLeftContour doesn't touch CenterRightContour but CenterRightContour * extends undesirably into the rivers. To handle this, we extrapolate forward from * CenterLeftContour using its last and second to last points, check for an intersection, * and then cull points and add the intersection as above. * * In the third case, CenterRightContour doesn't touch CenterLeftContour but CenterLeftContour * extends undesirably into the rivers. We handle this much the same way, extrapolating * backwards from the first and second points of CenterRightContour, checking for an intersecton, * and culling as needed. * * In the fourth case, neither contours touch each-other or extend into the rivers. In that case, * we extrapolate on both contours (forward for CenterLeft, backward for CenterRight) and add * their intersection without culling. */ public void RationalizeCellContours( IHexCell center, HexDirection direction ) { List <Vector2> centerLeftContour = CellEdgeContourCanon.GetContourForCellEdge(center, direction.Previous()).ToList(); List <Vector2> centerRightContour = CellEdgeContourCanon.GetContourForCellEdge(center, direction).ToList(); int lastOutsideLeftIndex = centerLeftContour.Count - 1; int lastOutsideRightIndex = 0; Vector2 contourIntersect = Vector2.zero; bool hasFoundIntersect = false; //We multiply our extrapolating vector by some relatively large number to make it more likely //that they intersect properly. for (; lastOutsideLeftIndex > 0; lastOutsideLeftIndex--) { if (Geometry2D.AreLineSegmentsCrossing( centerLeftContour[lastOutsideLeftIndex], centerLeftContour [lastOutsideLeftIndex - 1], out contourIntersect, centerRightContour[0], centerRightContour[0] + (centerRightContour[0] - centerRightContour[1]) * 10, out contourIntersect )) { hasFoundIntersect = true; break; } for (lastOutsideRightIndex = 0; lastOutsideRightIndex < centerRightContour.Count - 1; lastOutsideRightIndex++) { if (Geometry2D.AreLineSegmentsCrossing( centerLeftContour [lastOutsideLeftIndex], centerLeftContour [lastOutsideLeftIndex - 1], out contourIntersect, centerRightContour[lastOutsideRightIndex], centerRightContour[lastOutsideRightIndex + 1], out contourIntersect )) { hasFoundIntersect = true; break; } } if (hasFoundIntersect) { break; } } if (!hasFoundIntersect) { Vector2 lastLeft = centerLeftContour.Last(); Vector2 secondLastLeft = centerLeftContour[centerLeftContour.Count - 2]; if (Geometry2D.AreLineSegmentsCrossing( lastLeft, lastLeft + (lastLeft - secondLastLeft) * 10, out contourIntersect, centerRightContour[0], centerRightContour[0] + (centerRightContour[0] - centerRightContour[1]) * 10, out contourIntersect )) { hasFoundIntersect = true; } for (lastOutsideRightIndex = 0; lastOutsideRightIndex < centerRightContour.Count - 1; lastOutsideRightIndex++) { if (Geometry2D.AreLineSegmentsCrossing( lastLeft, lastLeft + (lastLeft - secondLastLeft) * 10, out contourIntersect, centerRightContour[lastOutsideRightIndex], centerRightContour[lastOutsideRightIndex + 1], out contourIntersect )) { hasFoundIntersect = true; break; } } } if (lastOutsideLeftIndex > 0) { centerLeftContour.RemoveRange(lastOutsideLeftIndex, centerLeftContour.Count - lastOutsideLeftIndex); } if (lastOutsideRightIndex < centerRightContour.Count - 1) { centerRightContour.RemoveRange(0, lastOutsideRightIndex + 1); } if (hasFoundIntersect) { centerLeftContour.Add(contourIntersect); centerRightContour.Insert(0, contourIntersect); } CellEdgeContourCanon.SetContourForCellEdge(center, direction.Previous(), centerLeftContour); CellEdgeContourCanon.SetContourForCellEdge(center, direction, centerRightContour); }