public void TriangulateEstuary(EdgeVertices edges1, EdgeVertices edges2, bool incomingRiver, Vector3 indices) { WaterShore.AddTriangle(edges2.v1, edges1.v2, edges1.v1); WaterShore.AddTriangle(edges2.v5, edges1.v5, edges1.v4); WaterShore.AddTriangleUV(new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(0f, 0f)); WaterShore.AddTriangleUV(new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(0f, 0f)); WaterShore.AddTriangleCellData(indices, Weights2, Weights1, Weights1); WaterShore.AddTriangleCellData(indices, Weights2, Weights1, Weights1); Estuaries.AddQuad(edges2.v1, edges1.v2, edges2.v2, edges1.v3); Estuaries.AddTriangle(edges1.v3, edges2.v2, edges2.v4); Estuaries.AddQuad(edges1.v3, edges1.v4, edges2.v4, edges2.v5); Estuaries.AddQuadUV(new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, 0f)); Estuaries.AddTriangleUV(new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, 1f)); Estuaries.AddQuadUV(0f, 0f, 0f, 1f); Estuaries.AddQuadCellData(indices, Weights2, Weights1, Weights2, Weights1); Estuaries.AddTriangleCellData(indices, Weights1, Weights2, Weights2); Estuaries.AddQuadCellData(indices, Weights1, Weights2); if (incomingRiver) { Estuaries.AddQuadUV2(new Vector2(1.5f, 1f), new Vector2(0.7f, 1.15f), new Vector2(1f, 0.8f), new Vector2(0.5f, 1.1f)); Estuaries.AddTriangleUV2(new Vector2(0.5f, 1.1f), new Vector2(1f, 0.8f), new Vector2(0f, 0.8f)); Estuaries.AddQuadUV2(new Vector2(0.5f, 1.1f), new Vector2(0.3f, 1.15f), new Vector2(0f, 0.8f), new Vector2(-0.5f, 1f)); } else { Estuaries.AddQuadUV2(new Vector2(-0.5f, -0.2f), new Vector2(0.3f, -0.35f), new Vector2(0f, 0f), new Vector2(0.5f, -0.3f)); Estuaries.AddTriangleUV2(new Vector2(0.5f, -0.3f), new Vector2(0f, 0f), new Vector2(1f, 0f)); Estuaries.AddQuadUV2(new Vector2(0.5f, -0.3f), new Vector2(0.7f, -0.35f), new Vector2(1f, 0f), new Vector2(1.5f, -0.2f)); } }
public void TriangulateRoadSegment(Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4, Vector3 v5, Vector3 v6, Color w1, Color w2, Vector3 indices) { Roads.AddQuad(v1, v2, v4, v5); Roads.AddQuad(v2, v3, v5, v6); Roads.AddQuadUV(0, 1, 0, 0); Roads.AddQuadUV(1, 0, 0, 0); Roads.AddQuadCellData(indices, w1, w2); Roads.AddQuadCellData(indices, w1, w2); }
void TriangulateRoadSegment(Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4, Vector3 v5, Vector3 v6, Color w1, Color w2, Vector3 indices) { roads.AddQuad(v1, v2, v4, v5); roads.AddQuad(v2, v3, v5, v6); roads.AddQuadUV(0f, 1f, 0f, 0f); roads.AddQuadUV(1f, 0f, 0f, 0f); roads.AddQuadCellData(indices, w1, w2); roads.AddQuadCellData(indices, w1, w2); }
protected static void TriangulateQuad(HexMesh mesh, EdgeVertices e1, EdgeVertices e2, Color c1, Color c2) { mesh.AddQuad(e1.v1, e1.v2, e2.v1, e2.v2); mesh.AddQuadColor(c1, c1, c2, c2); mesh.AddQuad(e1.v2, e1.v3, e2.v2, e2.v3); mesh.AddQuadColor(c1, c1, c2, c2); mesh.AddQuad(e1.v3, e1.v4, e2.v3, e2.v4); mesh.AddQuadColor(c1, c1, c2, c2); mesh.AddQuad(e1.v4, e1.v5, e2.v4, e2.v5); mesh.AddQuadColor(c1, c1, c2, c2); }
void TriangulatePointTerraces(Vector3 begin, HexCell beginCell, Vector3 left, HexCell leftCell, Vector3 right, HexCell rightCell) { Vector3 v3 = Hex.TerraceLerp(begin, left, 1); Vector3 v4 = Hex.TerraceLerp(begin, right, 1); Color w3 = Hex.TerraceLerp(weights1, weights2, 1); Color w4 = Hex.TerraceLerp(weights1, weights3, 1); Vector3 indices; indices.x = beginCell.Index; indices.y = leftCell.Index; indices.z = rightCell.Index; terrain.AddTriangle(begin, v3, v4); terrain.AddTriangleCellData(indices, weights1, w3, w4); for (int i = 2; i < Hex.terracesSteps; i++) { Vector3 v1 = v3; Vector3 v2 = v4; Color w1 = w3; Color w2 = w4; v3 = Hex.TerraceLerp(begin, left, i); v4 = Hex.TerraceLerp(begin, right, i); w3 = Hex.TerraceLerp(weights1, weights2, i); w4 = Hex.TerraceLerp(weights1, weights3, i); terrain.AddQuad(v1, v2, v3, v4); terrain.AddQuadCellData(indices, w1, w2, w3, w4); } terrain.AddQuad(v3, v4, left, right); terrain.AddQuadCellData(indices, w3, w4, weights2, weights3); }
void TriangulateCornerTerraces(Vector3 begin, HexCell beginCell, Vector3 left, HexCell leftCell, Vector3 right, HexCell rightCell) { Vector3 v3 = HexMetrics.TerraceLerp(begin, left, 1); Vector3 v4 = HexMetrics.TerraceLerp(begin, right, 1); Color c3 = HexMetrics.TerraceLerp(beginCell.Color, leftCell.Color, 1); Color c4 = HexMetrics.TerraceLerp(beginCell.Color, rightCell.Color, 1); terrain.AddTriangle(begin, v3, v4); terrain.AddTriangleColor(beginCell.Color, c3, c4); for (int i = 2; i < HexMetrics.terraceSteps; i++) { Vector3 v1 = v3; Vector3 v2 = v4; Color c1 = c3; Color c2 = c4; v3 = HexMetrics.TerraceLerp(begin, left, i); v4 = HexMetrics.TerraceLerp(begin, right, i); c3 = HexMetrics.TerraceLerp(beginCell.Color, leftCell.Color, i); c4 = HexMetrics.TerraceLerp(beginCell.Color, rightCell.Color, i); terrain.AddQuad(v1, v2, v3, v4); terrain.AddQuadColor(c1, c2, c3, c4); } terrain.AddQuad(v3, v4, left, right); terrain.AddQuadColor(c3, c4, leftCell.Color, rightCell.Color); }
void TriangulateEdgeStrip(EdgeVertices e1, Color w1, float index1, EdgeVertices e2, Color w2, float index2, bool hasRoad = false) { terrain.AddQuad(e1.v1, e1.v2, e2.v1, e2.v2); terrain.AddQuad(e1.v2, e1.v3, e2.v2, e2.v3); terrain.AddQuad(e1.v3, e1.v4, e2.v3, e2.v4); terrain.AddQuad(e1.v4, e1.v5, e2.v4, e2.v5); Vector3 indices; indices.x = indices.z = index1; indices.y = index2; terrain.AddQuadCellData(indices, w1, w2); terrain.AddQuadCellData(indices, w1, w2); terrain.AddQuadCellData(indices, w1, w2); terrain.AddQuadCellData(indices, w1, w2); if (hasRoad) { TriangulateRoadSegment(e1.v2, e1.v3, e1.v4, e2.v2, e2.v3, e2.v4, w1, w2, indices); } }
public void TriangulateWithRiver(HexDirection dir, HexCell cell, Vector3 center, EdgeVertices edges) { Vector3 centerL; Vector3 centerR; float centerLinePinch = 2.0f / 3.0f; if (cell.HasRiverThroughEdge(dir.Opposite())) { centerL = center + HexMetrics.GetFirstSolidCorner(dir.Previous()) * HexMetrics.SubdivideFraction; centerR = center + HexMetrics.GetSecondSolidCorner(dir.Next()) * HexMetrics.SubdivideFraction; center = (centerL + centerR) / 2.0f; } else if (cell.HasRiverThroughEdge(dir.Next())) { centerL = center; centerR = Vector3.Lerp(center, edges.v5, centerLinePinch); } else if (cell.HasRiverThroughEdge(dir.Previous())) { centerL = Vector3.Lerp(center, edges.v1, centerLinePinch); centerR = center; } else if (cell.HasRiverThroughEdge(dir.Next2())) { centerL = center; centerR = center + HexMetrics.GetSolidEdgeMiddle(dir.Next()) * (0.5f * HexMetrics.InnerToOuter); } else { centerL = center + HexMetrics.GetSolidEdgeMiddle(dir.Previous()) * (0.5f * HexMetrics.InnerToOuter); centerR = center; } EdgeVertices modifiedEdges = new EdgeVertices(Vector3.Lerp(centerL, edges.v1, 0.5f), Vector3.Lerp(centerR, edges.v5, 0.5f)); modifiedEdges.v3.y = center.y = edges.v3.y; TriangulateEdgeStrip(modifiedEdges, Weights1, cell.TerrainTypeIndex, edges, Weights1, cell.CellIndex); Terrain.AddTriangle(centerL, modifiedEdges.v1, modifiedEdges.v2); Terrain.AddQuad(centerL, center, modifiedEdges.v2, modifiedEdges.v3); Terrain.AddQuad(center, centerR, modifiedEdges.v3, modifiedEdges.v4); Terrain.AddTriangle(centerR, modifiedEdges.v4, modifiedEdges.v5); Vector3 indices = new Vector3(cell.CellIndex, cell.CellIndex, cell.CellIndex); Terrain.AddTriangleCellData(indices, Weights1); Terrain.AddQuadCellData(indices, Weights1); Terrain.AddQuadCellData(indices, Weights1); Terrain.AddTriangleCellData(indices, Weights1); if (!cell.IsUnderwater) { bool reverse = cell.IncomingRiverDirection == dir; TriangulateRiverQuad(centerL, centerR, modifiedEdges.v2, modifiedEdges.v4, cell.RiverSurfaceY, 0.4f, reverse, indices); TriangulateRiverQuad(modifiedEdges.v2, modifiedEdges.v4, edges.v2, edges.v4, cell.RiverSurfaceY, 0.6f, reverse, indices); } }
/* Creates a quad stretching from a cell's solid boundary to its true edge*/ void TriangulateEdge(HexDirection direction, HexCell cell) { Vector3 center = cell.transform.localPosition; EdgeVertices e1 = new EdgeVertices( center + HexMetrics.GetFirstSolidCorner(direction), center + HexMetrics.GetSecondSolidCorner(direction) ); EdgeVertices e2 = new EdgeVertices( center + HexMetrics.GetFirstCorner(direction), center + HexMetrics.GetSecondCorner(direction) ); edgeMesh.AddQuad(e1, e2); }
void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { Vector3 centerL, centerR; if (cell.HasRiverThroughEdge(direction.Opposite())) { centerL = center + HexMetrics.GetFirstSolidCorner(direction.Previous()) * 0.25f; centerR = center + HexMetrics.GetSecondSolidCorner(direction.Next()) * 0.25f; } else if (cell.HasRiverThroughEdge(direction.Next())) { centerL = center; centerR = Vector3.Lerp(center, e.v5, 2f / 3f); } else if (cell.HasRiverThroughEdge(direction.Previous())) { centerL = Vector3.Lerp(center, e.v1, 2f / 3f); centerR = center; } else if (cell.HasRiverThroughEdge(direction.Next2())) { centerL = center; centerR = center + HexMetrics.GetSolidEdgeMiddle(direction.Next()) * (0.5f * HexMetrics.innerToOuter); } else { centerL = center + HexMetrics.GetSolidEdgeMiddle(direction.Previous()) * (0.5f * HexMetrics.innerToOuter); centerR = center; } center = Vector3.Lerp(centerL, centerR, 0.5f); EdgeVertices m = new EdgeVertices( Vector3.Lerp(centerL, e.v1, 0.5f), Vector3.Lerp(centerR, e.v5, 0.5f), 1f / 6f ); m.v3.y = center.y = e.v3.y; TriangulateEdgeStrip(m, weights1, cell.Index, e, weights1, cell.Index); terrain.AddTriangle(centerL, m.v1, m.v2); terrain.AddQuad(centerL, center, m.v2, m.v3); terrain.AddQuad(center, centerR, m.v3, m.v4); terrain.AddTriangle(centerR, m.v4, m.v5); Vector3 indices; indices.x = indices.y = indices.z = cell.Index; terrain.AddTriangleCellData(indices, weights1); terrain.AddQuadCellData(indices, weights1); terrain.AddQuadCellData(indices, weights1); terrain.AddTriangleCellData(indices, weights1); if (!cell.IsUnderWater) { bool reversed = cell.IncomingRiver == direction; TriangulateRiverQuad(centerL, centerR, m.v2, m.v4, cell.RiverSurfaceY, 0.4f, reversed, indices); TriangulateRiverQuad(m.v2, m.v4, e.v2, e.v4, cell.RiverSurfaceY, 0.6f, reversed, indices); } }
public override void Triangulate(HexMesh mesh) { Vector3 v1 = beginCorner; Vector3 v2 = beginCorner; Color c1 = beginCell.Color; Color c2 = beginCell.Color; for (int step = 1; step < HexMetrics.terraceSteps + 1; ++step) { Vector3 v3 = HexMetrics.TerraceLerp(beginCorner, leftCorner, step); Vector3 v4 = HexMetrics.TerraceLerp(beginCorner, rightCorner, step); Color c3 = HexMetrics.ColorLerp(beginCell.Color, leftCell.Color, step); Color c4 = HexMetrics.ColorLerp(beginCell.Color, rightCell.Color, step); if (step == 1) { mesh.AddTriangle(v1, v3, v4); mesh.AddTriangleColor(c1, c3, c4); } else { mesh.AddQuad(v1, v2, v3, v4); mesh.AddQuadColor(c1, c2, c3, c4); } v1 = v3; v2 = v4; c1 = c3; c2 = c4; } }
public void TriangulateOpenWater(HexDirection dir, HexCell cell, HexCell neighbour, Vector3 center) { Vector3 c1 = center + HexMetrics.GetFirstWaterCorner(dir); Vector3 c2 = center + HexMetrics.GetSecondWaterCorner(dir); Water.AddTriangle(center, c1, c2); Vector3 indices = new Vector3(cell.CellIndex, cell.CellIndex, cell.CellIndex); Water.AddTriangleCellData(indices, Weights1); if (dir <= HexDirection.SE && neighbour != null) { Vector3 bridge = HexMetrics.GetWaterBridge(dir); Vector3 e1 = c1 + bridge; Vector3 e2 = c2 + bridge; Water.AddQuad(c1, c2, e1, e2); indices.y = neighbour.CellIndex; Water.AddQuadCellData(indices, Weights1, Weights2); if (dir <= HexDirection.E) { HexCell nextNeightbour = cell.GetNeighbour(dir.Next()); if (nextNeightbour == null || !nextNeightbour.IsUnderwater) { return; } Water.AddTriangle(c2, e2, c2 + HexMetrics.GetWaterBridge(dir.Next())); indices.z = nextNeightbour.CellIndex; Water.AddTriangleCellData(indices, Weights1, Weights2, Weights3); } } }
void TriangulateOpenWater(HexDirection direction, HexCell cell, HexCell neighbor, Vector3 center) { Vector3 c1 = center + HexMetrics.GetFirstWaterCorner(direction); Vector3 c2 = center + HexMetrics.GetSecondWaterCorner(direction); water.AddTriangle(center, c1, c2); Vector3 indices; indices.x = indices.y = indices.z = cell.Index; water.AddTriangleCellData(indices, weights1); if (direction <= HexDirection.SE && neighbor != null) { Vector3 bridge = HexMetrics.GetWaterBridge(direction); Vector3 e1 = c1 + bridge; Vector3 e2 = c2 + bridge; water.AddQuad(c1, c2, e1, e2); indices.y = neighbor.Index; water.AddQuadCellData(indices, weights1, weights2); if (direction <= HexDirection.E) { HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); if (nextNeighbor == null || !nextNeighbor.IsUnderWater) { return; } water.AddTriangle(c2, e2, c2 + HexMetrics.GetWaterBridge(direction.Next())); indices.z = nextNeighbor.Index; water.AddTriangleCellData(indices, weights1, weights2, weights3); } } }
void TriangulateWallStrip(HexDirection d, HexCell cell) { HexDirection castDir = d.Opposite(); HexCell n = cell.GetNeighbor(castDir); if (CheckCellValid(n)) { //limit to prevent infinite loops if something goes wrong for (int i = 0; i < 10; i++) { HexCell n2 = n.GetNeighbor(castDir); if (CheckCellValid(n2)) { n = n2; } else { break; } } //n is final cell Vector3 offset = new Vector3(0, wallHeight, 0); EdgeVertices e1 = new EdgeVertices( cell.transform.localPosition + HexMetrics.GetFirstSolidCorner(castDir), n.transform.localPosition + HexMetrics.GetSecondSolidCorner(d) ); EdgeVertices e2 = new EdgeVertices( e1.v1 + offset, e1.v2 + offset ); wallMesh.AddQuad(e1, e2); EdgeVertices e3 = new EdgeVertices( offset + cell.transform.localPosition + HexMetrics.GetFirstCorner(castDir), offset + n.transform.localPosition + HexMetrics.GetSecondCorner(d) ); wallMesh.AddQuad(e2, e3); EdgeVertices e4 = new EdgeVertices( offset + cell.transform.localPosition + HexMetrics.GetFirstCorner(castDir.Previous()), offset + n.transform.localPosition + HexMetrics.GetSecondCorner(d.Next()) ); wallMesh.AddQuad(e3, e4); } }
void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { Vector3 centerL, centerR; if (cell.HasRiverThroughEdge(direction.Opposite())) { centerL = center + HexMetrics.GetFirstSolidCorner(direction.Previous()) * 0.25f; centerR = center + HexMetrics.GetSecondSolidCorner(direction.Next()) * 0.25f; } else if (cell.HasRiverThroughEdge(direction.Next())) { centerL = center; centerR = Vector3.Lerp(center, e.v5, 2f / 3f); } else if (cell.HasRiverThroughEdge(direction.Previous())) { centerL = Vector3.Lerp(center, e.v1, 2f / 3f); centerR = center; } else if (cell.HasRiverThroughEdge(direction.Next2())) { centerL = center; centerR = center + HexMetrics.GetSolidEdgeMiddle(direction.Next()) * (0.5f * HexMetrics.kInnerToOuter); } else { centerL = center + HexMetrics.GetSolidEdgeMiddle(direction.Previous()) * (0.5f * HexMetrics.kInnerToOuter); centerR = center; } center = Vector3.Lerp(centerL, centerR, 0.5f); EdgeVertices m = new EdgeVertices( Vector3.Lerp(centerL, e.v1, 0.5f), Vector3.Lerp(centerR, e.v5, 0.5f), 1f / 6f ); m.v3.y = center.y = e.v3.y; TriangulateEdgeStrip(m, cell.Color, e, cell.Color); terrain.AddTriangle(centerL, m.v1, m.v2); terrain.AddTriangleColor(cell.Color); terrain.AddQuad(centerL, center, m.v2, m.v3); terrain.AddQuadColor(cell.Color); terrain.AddQuad(center, centerR, m.v3, m.v4); terrain.AddQuadColor(cell.Color); terrain.AddTriangle(centerR, m.v4, m.v5); terrain.AddTriangleColor(cell.Color); if (!cell.IsUnderwater) { bool reversed = cell.IncomingRiver == direction; TriangulateRiverQuad(centerL, centerR, m.v2, m.v4, cell.RiverSurfaceY, cell.RiverSurfaceY, 0.5f, HexMetrics.kRiverSolidUVStep, reversed); TriangulateRiverQuad(m.v2, m.v4, e.v2, e.v4, cell.RiverSurfaceY, cell.RiverSurfaceY, 0.5f + HexMetrics.kRiverSolidUVStep, HexMetrics.kRiverSolidUVStep, reversed); } }
/// <summary> /// 三角化角落阶梯,用于三角化三边分别是:平、阶、阶的角落 /// </summary> /// <param name="begin"></param> /// <param name="beginCell">三角形阶梯所在六边形</param> /// <param name="left"></param> /// <param name="leftCell"></param> /// <param name="right"></param> /// <param name="rightCell"></param> void TriangulateCornerTerraces(Vector3 begin, HexCell beginCell, Vector3 left, HexCell leftCell, Vector3 right, HexCell rightCell) { Vector3 v3 = HexMetrics.TerraceLerp(begin, left, 1); Vector3 v4 = HexMetrics.TerraceLerp(begin, right, 1); Color c3 = HexMetrics.TerraceLerp(weights1, weights2, 1); Color c4 = HexMetrics.TerraceLerp(weights1, weights3, 1); Vector3 indices; indices.x = beginCell.Index; indices.y = leftCell.Index; indices.z = rightCell.Index; // 先生成第一个三角形 terrain.AddTriangle(begin, v3, v4); // 顶点和三角索引 terrain.AddTriangleCellData(indices, weights1, c3, c4); // 地形类型和splat颜色 // 后面的阶梯生成四边形 for (int i = 2; i <= HexMetrics.terraceSteps; i++) { Vector3 v1 = v3; Vector3 v2 = v4; Color c1 = c3; Color c2 = c4; v3 = HexMetrics.TerraceLerp(begin, left, i); v4 = HexMetrics.TerraceLerp(begin, right, i); c3 = HexMetrics.TerraceLerp(weights1, weights2, i); c4 = HexMetrics.TerraceLerp(weights1, weights3, i); terrain.AddQuad(v1, v2, v3, v4); terrain.AddQuadCellData(indices, c1, c2, c3, c4); } }
void TriangulateEdgeStrip(EdgeVertices e1, Color c1, EdgeVertices e2, Color c2) { terrain.AddQuad(e1.v1, e1.v2, e2.v1, e2.v2); terrain.AddQuadColor(c1, c2); terrain.AddQuad(e1.v2, e1.v3, e2.v2, e2.v3); terrain.AddQuadColor(c1, c2); terrain.AddQuad(e1.v3, e1.v4, e2.v3, e2.v4); terrain.AddQuadColor(c1, c2); terrain.AddQuad(e1.v4, e1.v5, e2.v4, e2.v5); terrain.AddQuadColor(c1, c2); }
/// <summary> /// 三角化河口 /// </summary> /// <param name="e1">自身纯色区扇形边(弧)</param> /// <param name="e2">邻居纯色区扇形边(弧)</param> /// <param name="incomingRiver">是否是流入河</param> /// <param name="indices">临近六边形</param> void TriangulateEstuary(EdgeVertices e1, EdgeVertices e2, bool incomingRiver, Vector3 indices) { waterShore.AddTriangle(e2.v1, e1.v2, e1.v1); waterShore.AddTriangle(e2.v5, e1.v5, e1.v4); waterShore.AddTriangleUV(new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(0f, 0f)); waterShore.AddTriangleUV(new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(0f, 0f)); waterShore.AddTriangleCellData(indices, weights2, weights1, weights1); // 第一个顶点位于邻居六边形内所以用weights2,第二三个顶点位于自身六边形所以用weights1 waterShore.AddTriangleCellData(indices, weights2, weights1, weights1); // 河口顶点 : e2: v1----v5 // e1: v2--v4 // estuaries.AddQuad(e2.v1, e1.v2, e2.v2, e1.v3); estuaries.AddTriangle(e1.v3, e2.v2, e2.v4); estuaries.AddQuad(e1.v3, e1.v4, e2.v4, e2.v5); // 该UV的v用于判断离岸远近,u用于匹配瀑布水流消失插值(瀑布下方为1,扩散外围为0) estuaries.AddQuadUV(new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(1f, 1f), new Vector2(0f, 0f)); estuaries.AddTriangleUV(new Vector2(0f, 0f), new Vector2(1f, 1f), new Vector2(1f, 1f)); estuaries.AddQuadUV(new Vector2(0f, 0f), new Vector2(0f, 0f), new Vector2(1f, 1f), new Vector2(0f, 1f)); // 六边形格子数据 estuaries.AddQuadCellData(indices, weights2, weights1, weights2, weights1); estuaries.AddTriangleCellData(indices, weights1, weights2, weights2); estuaries.AddQuadCellData(indices, weights1, weights2); // 如果是流入河流的河口 if (incomingRiver) { // uv2 用于匹配河水流动, v为河水流动方向 // 由于是河口位于桥的下面,所以v坐标是0.8~1, // 由于水平面纯色区占比只有0.6,陆地水面交接处的桥是0.2+0.4,比陆地与陆地交接处的桥(0.2+0.2)大了50%,所以v坐标扩大50%,变成0.8~1.1 estuaries.AddQuadUV2(new Vector2(1.5f, 1f), new Vector2(0.7f, 1.15f), new Vector2(1f, 0.8f), new Vector2(0.5f, 1.1f)); estuaries.AddTriangleUV2(new Vector2(0.5f, 1.1f), new Vector2(1f, 0.8f), new Vector2(0f, 0.8f)); estuaries.AddQuadUV2(new Vector2(0.5f, 1.1f), new Vector2(0.3f, 1.15f), new Vector2(0f, 0.8f), new Vector2(-0.5f, 1f)); } // 如果是流出河流的河口(翻转uv) else { estuaries.AddQuadUV2(new Vector2(-0.5f, -0.2f), new Vector2(0.3f, -0.35f), new Vector2(0f, 0f), new Vector2(0.5f, -0.3f)); estuaries.AddTriangleUV2(new Vector2(0.5f, -0.3f), new Vector2(0f, 0f), new Vector2(1f, 0f)); estuaries.AddQuadUV2(new Vector2(0.5f, -0.3f), new Vector2(0.7f, -0.35f), new Vector2(1f, 0f), new Vector2(1.5f, -0.2f)); } }
void Triangulate(HexDirection direction, HexCell cell) { Vector3 center = cell.Position; Vector3 v1 = center + HexMetrics.GetFirstInnerCorner(direction); Vector3 v2 = center + HexMetrics.GetSecondInnerCorner(direction); Vector3 v1OuterBump = center + HexMetrics.GetFirstBumpOuterCorner(direction); Vector3 v2OuterBump = center + HexMetrics.GetSecondBumpOuterCorner(direction); Vector3 indices; indices.x = indices.y = indices.z = cell.Index; terrain.AddTriangle(center, v1, v2); terrain.AddTriangleCellData(indices, weights1); terrain.AddQuad(v1, v2, v1OuterBump, v2OuterBump); if (cell.IsUnderwater) { terrain.AddQuadCellData(indices, weights1, weights1); } else { terrain.AddQuadCellData(indices, terrainColorBump, terrainColorBump); } if (direction <= HexDirection.SE) { TriangulateConnection(direction, cell, v1OuterBump, v2OuterBump); } if (cell.IsUnderwater) { TriangulateWater(direction, cell, center); } if (!cell.IsUnderwater) { features.AddFeature(cell, (center + v1 + v2) * (1f / 3f)); } }
private void AddWallSegment(Vector3 nearLeft, Vector3 farLeft, Vector3 nearRight, Vector3 farRight) { nearLeft = HexMetrics.Perturb(nearLeft); farLeft = HexMetrics.Perturb(farLeft); nearRight = HexMetrics.Perturb(nearRight); farRight = HexMetrics.Perturb(farRight); Vector3 left = HexMetrics.WallLerp(nearLeft, farLeft); Vector3 right = HexMetrics.WallLerp(nearRight, farRight); Vector3 leftThicknessOffset = HexMetrics.WallThicknessOffset(nearLeft, farLeft); Vector3 rightThicknessOffset = HexMetrics.WallThicknessOffset(nearRight, farRight); float leftTop = left.y + HexMetrics.wallHeight; float rightTop = right.y + HexMetrics.wallHeight; Vector3 v1; Vector3 v2; Vector3 v3 = v1 = left - leftThicknessOffset; Vector3 v4 = v2 = right - rightThicknessOffset; v3.y = leftTop; v4.y = rightTop; walls.AddQuad(v1, v2, v3, v4); Vector3 t1 = v3; Vector3 t2 = v4; v1 = v3 = left + leftThicknessOffset; v2 = v4 = right + rightThicknessOffset; v3.y = leftTop; v4.y = rightTop; walls.AddQuad(v2, v1, v4, v3); walls.AddQuad(t1, t2, v3, v4); }
private void TriangulateEdgeStrip(EdgeVertices e1, Color c1, EdgeVertices e2, Color c2, bool hasWall = false) { _terrain.AddQuad(e1.v1, e1.v2, e2.v1, e2.v2); _terrain.AddQuadColor(c1, c2); _terrain.AddQuad(e1.v2, e1.v3, e2.v2, e2.v3); _terrain.AddQuadColor(c1, c2); _terrain.AddQuad(e1.v3, e1.v4, e2.v3, e2.v4); _terrain.AddQuadColor(c1, c2); _terrain.AddQuad(e1.v4, e1.v5, e2.v4, e2.v5); _terrain.AddQuadColor(c1, c2); if (hasWall) { TriangulateWallSegment(e1.v2, e1.v3, e1.v4, e2.v2, e2.v3, e2.v4); } }
void TriangulateRiverQuad(Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4, float y1, float y2, float v, bool reversed, Vector3 indices) { v1.y = v2.y = y1; v3.y = v4.y = y2; rivers.AddQuad(v1, v2, v3, v4); if (reversed) { rivers.AddQuadUV(1f, 0f, 0.8f - v, 0.6f - v); } else { rivers.AddQuadUV(0f, 1f, v, v + 0.2f); } rivers.AddQuadCellData(indices, weights1, weights2); }
void TriangulateCornerTerraces(Vector3 begin, HexCell beginCell, Vector3 left, HexCell leftCell, Vector3 right, HexCell rightCell) { Vector3 v3 = HexMetrics.TerraceLerp(begin, left, 1); Vector3 v4 = HexMetrics.TerraceLerp(begin, right, 1); Color c3 = HexMetrics.TerraceLerp(beginCell.Color, leftCell.Color, 1); Color c4 = HexMetrics.TerraceLerp(beginCell.Color, rightCell.Color, 1); terrain.AddTriangle(begin, v3, v4); terrain.AddTriangleColor(beginCell.Color, c3, c4); terrain.AddQuad(v3, v4, left, right); terrain.AddQuadColor(c3, c4, leftCell.Color, rightCell.Color); }
/* * 连接三角形 针对left right都是梯田的 */ void TriangulateCornerTerraces( Vector3 begin, HexCell beginCell, Vector3 left, HexCell leftCell, Vector3 right, HexCell rightCell) { //在slope-slope-flat类型中,和平台的插值TriangulateEdgeTerraces方法一样 Vector3 v3 = HexMetrics.TerraceLerp(begin, left, 1); Vector3 v4 = HexMetrics.TerraceLerp(begin, right, 1); Color c3 = HexMetrics.TerraceLerp(color1, color2, 1); Color c4 = HexMetrics.TerraceLerp(color1, color3, 1); //添加地形贴图UV Vector3 types; types.x = beginCell.TerrainTypeIndex; types.y = leftCell.TerrainTypeIndex; types.z = rightCell.TerrainTypeIndex; terrain.AddTriangle(begin, v3, v4); terrain.AddTriangleColor(color1, c3, c4); terrain.AddTriangleTerrainTypes(types); for (int i = 2; i < HexMetrics.terraceSteps; i++) { Vector3 v1 = v3; Vector3 v2 = v4; Color c1 = c3; Color c2 = c4; v3 = HexMetrics.TerraceLerp(begin, left, i); v4 = HexMetrics.TerraceLerp(begin, right, i); c3 = HexMetrics.TerraceLerp(color1, color2, i); c4 = HexMetrics.TerraceLerp(color1, color3, i); terrain.AddQuad(v1, v2, v3, v4); terrain.AddQuadColor(c1, c2, c3, c4); terrain.AddQuadTerrainTypes(types); } terrain.AddQuad(v3, v4, left, right); terrain.AddQuadColor(c3, c4, color2, color3); terrain.AddQuadTerrainTypes(types); }
/// <summary> /// 三角化角部连接,当角部三角形的边是两个斜坡与一个平地时 /// </summary> /// <param name="begin"></param> /// <param name="beginCell"></param> /// <param name="left"></param> /// <param name="leftCell"></param> /// <param name="right"></param> /// <param name="rightCell"></param> void TriangulateCornerTerraces(Vector3 begin, HexCell beginCell, Vector3 left, HexCell leftCell, Vector3 right, HexCell rightCell) { Vector3 v3 = HexMetrics.TerraceLerp(begin, left, 1); Vector3 v4 = HexMetrics.TerraceLerp(begin, right, 1); Color w3 = HexMetrics.TerraceLerp(weights1, weights2, 1); Color w4 = HexMetrics.TerraceLerp(weights1, weights3, 1); Vector3 indices; indices.x = beginCell.Index; indices.y = leftCell.Index; indices.z = rightCell.Index; terrain.AddTriangle(begin, v3, v4); terrain.AddTriangleCellData(indices, weights1, w3, w4); //terrain.AddTriangleColor(color1, c3, c4); //terrain.AddTriangulateTerrainType(types); for (int i = 2; i < HexMetrics.terraceSteps; i++) { Vector3 v1 = v3; Vector3 v2 = v4; Color w1 = w3; Color w2 = w4; v3 = HexMetrics.TerraceLerp(begin, left, i); v4 = HexMetrics.TerraceLerp(begin, right, i); w3 = HexMetrics.TerraceLerp(weights1, weights2, i); w4 = HexMetrics.TerraceLerp(weights1, weights3, i); terrain.AddQuad(v1, v2, v3, v4); terrain.AddQuadCellData(indices, w1, w2, w3, w4); //terrain.AddQuadColor(c1, c2, c3, c4); //terrain.AddQuadTerrainType(types); } terrain.AddQuad(v3, v4, left, right); terrain.AddQuadCellData(indices, w3, w4, weights2, weights3); //terrain.AddQuadColor(c3, c4, color2, color3); //terrain.AddQuadTerrainType(types); }
/// <summary> /// 三角化河流四边形 /// </summary> /// <param name="v1">自身六边形内的顶点</param> /// <param name="v2">自身六边形内的顶点</param> /// <param name="v3">邻居六边形内的顶点</param> /// <param name="v4">邻居六边形内的顶点</param> /// <param name="y1">自身高度(河水平面)</param> /// <param name="y2">邻居高度(河水平面)</param> /// <param name="v">UV坐标的V</param> /// <param name="reversed"></param> void TriangulateRiverQuad(Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4, float y1, float y2, float v, bool reversed, Vector3 indices) { v1.y = v2.y = y1; v3.y = v4.y = y2; // 添加顶点 rivers.AddQuad(v1, v2, v3, v4); // 添加UV坐标(把一个六边形内的河水(六边形内四个四边形,加上桥,总共五个四边形) // UV坐标的v分为五等分:0~0.2, 0.2~0.4, 0.4~0.6, 0.6~0.8, 0.8~1) if (reversed) { rivers.AddQuadUV(1f, 0f, 0.8f - v, 0.6f - v); // 流入河流 } else { rivers.AddQuadUV(0f, 1f, v, v + 0.2f); // 流出河流 } rivers.AddQuadCellData(indices, weights1, weights2); }
void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { //outer walls Vector3 centerL, centerR; if (cell.HasRiverThroughEdge(direction.Opposite())) { centerL = center + HexMetric.GetFirstSolidCorner(direction.Previous()) * 0.25f; centerR = center + HexMetric.GetSecondSolidCorner(direction.Next()) * 0.25f; } // sharp turns else if (cell.HasRiverThroughEdge(direction.Next())) { centerL = center; centerR = Vector3.Lerp(center, e.v5, 2f / 3f); } else if (cell.HasRiverThroughEdge(direction.Previous())) { centerL = Vector3.Lerp(center, e.v1, 2f / 3f); centerR = center; } // two way turns else if (cell.HasRiverThroughEdge(direction.Next2())) { centerL = center; centerR = center + HexMetric.GetSolidEdgeMiddle(direction.Next()) * (0.5f * HexMetric.innerToOuter); } else { centerL = center + HexMetric.GetSolidEdgeMiddle(direction.Previous()) * (0.5f * HexMetric.innerToOuter); centerR = center; } //mid point of channel EdgeVertices m = new EdgeVertices(Vector3.Lerp(centerL, e.v1, 0.5f), Vector3.Lerp(centerR, e.v5, 0.5f), 1f / 6f); m.v3.y = center.y = e.v3.y; //fill area TriangulateEdgeStrip(m, color1, cell.TerrainTypeIndex, e, color1, cell.TerrainTypeIndex); terrain.AddTriangle(centerL, m.v1, m.v2); terrain.AddQuad(centerL, center, m.v2, m.v3); terrain.AddQuad(center, centerR, m.v3, m.v4); terrain.AddTriangle(centerR, m.v4, m.v5); terrain.AddTriangleColor(color1); terrain.AddQuadColor(color1); terrain.AddQuadColor(color1); terrain.AddTriangleColor(color1); Vector3 types; types.x = types.y = types.z = cell.TerrainTypeIndex; terrain.AddTriangleTerrainTypes(types); terrain.AddQuadTerrainTypes(types); terrain.AddQuadTerrainTypes(types); terrain.AddTriangleTerrainTypes(types); //river water quads if (!cell.IsUnderwater) { bool reversed = cell.IncomingRiver == direction; TriangulateRiverQuad(centerL, centerR, m.v2, m.v4, cell.RiverSurfaceY, 0.4f, reversed); TriangulateRiverQuad(m.v2, m.v4, e.v2, e.v4, cell.RiverSurfaceY, 0.6f, reversed); } }
/// <summary> /// Creates the triangles for a side of the hexagon, with river passing through (incoming and outgoing river) at this side. /// </summary> void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) { Vector3 centerL, centerR; if (cell.HasRiverThroughEdge(direction.Opposite())) // If river flows forward through the cell // Extend center into line { centerL = center + HexMetrics.GetFirstSolidCorner(direction.Previous()) * 0.25f; centerR = center + HexMetrics.GetSecondSolidCorner(direction.Next()) * 0.25f; } else if (cell.HasRiverThroughEdge(direction.Next())) // If river bends sharply in next dir { centerL = center; centerR = Vector3.Lerp(center, e.v5, 2f / 3f); } else if (cell.HasRiverThroughEdge(direction.Previous())) // If river bends sharply in prev dir { centerL = Vector3.Lerp(center, e.v1, 2f / 3f); centerR = center; } else if (cell.HasRiverThroughEdge(direction.Next2())) // River bends smoothly to next.next dir { centerL = center; centerR = center + HexMetrics.GetSolidEdgeMiddle(direction.Next()) * (0.5f * HexMetrics.InnerToOuter); } else // River bends smoothly to previous.previous dir { centerL = center + HexMetrics.GetSolidEdgeMiddle(direction.Previous()) * (0.5f * HexMetrics.InnerToOuter); centerR = center; } center = Vector3.Lerp(centerL, centerR, 0.5f); // Average center to serve all cases // Edge 1/2 the way from edge and cell center EdgeVertices m = new EdgeVertices( Vector3.Lerp(centerL, e.v1, 0.5f), Vector3.Lerp(centerR, e.v5, 0.5f), 1f / 6f ); m.v3.y = center.y = e.v3.y; // Lower middle edge and center to river bed TriangulateEdgeStrip(m, weights1, cell.Index, e, weights1, cell.Index); // Final gap between the middle edge and the center // Geo Terrain.AddTriangle(centerL, m.v1, m.v2); Terrain.AddQuad(centerL, center, m.v2, m.v3); Terrain.AddQuad(center, centerR, m.v3, m.v4); Terrain.AddTriangle(centerR, m.v4, m.v5); // Splat + Terrain Types Vector3 indices; indices.x = indices.y = indices.z = cell.Index; Terrain.AddTriangleCellData(indices, weights1); Terrain.AddQuadCellData(indices, weights1); Terrain.AddQuadCellData(indices, weights1); Terrain.AddTriangleCellData(indices, weights1); if (!cell.IsUnderwater) // No river water surface when underwater, river bed allowed // River water surface { bool reversed = cell.IncomingRiver == direction; TriangulateRiverQuad(centerL, centerR, m.v2, m.v4, cell.RiverSurfaceY, 0.4f, reversed, indices); TriangulateRiverQuad(m.v2, m.v4, e.v2, e.v4, cell.RiverSurfaceY, 0.6f, reversed, indices); } }
void TriangulateEstuary(EdgeVertices e1, EdgeVertices e2, bool incomingRiver, Vector3 indices) { waterShore.AddTriangle(e2.v1, e1.v2, e1.v1); waterShore.AddTriangle(e2.v5, e1.v5, e1.v4); waterShore.AddTriangleUV( new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(0f, 0f) ); waterShore.AddTriangleUV( new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(0f, 0f) ); waterShore.AddTriangleCellData(indices, weights2, weights1, weights1); waterShore.AddTriangleCellData(indices, weights2, weights1, weights1); estuaries.AddQuad(e2.v1, e1.v2, e2.v2, e1.v3); estuaries.AddTriangle(e1.v3, e2.v2, e2.v4); estuaries.AddQuad(e1.v3, e1.v4, e2.v4, e2.v5); estuaries.AddQuadUV( new Vector2(0f, 1f), new Vector2(0f, 0f), new Vector2(1f, 1f), new Vector2(0f, 0f) ); estuaries.AddTriangleUV( new Vector2(0f, 0f), new Vector2(1f, 1f), new Vector2(1f, 1f) ); estuaries.AddQuadUV( new Vector2(0f, 0f), new Vector2(0f, 0f), new Vector2(1f, 1f), new Vector2(0f, 1f) ); estuaries.AddQuadCellData(indices, weights2, weights1, weights2, weights1); estuaries.AddTriangleCellData(indices, weights2, weights1, weights2); estuaries.AddQuadCellData(indices, weights1, weights2); if (incomingRiver) { estuaries.AddQuadUV2( new Vector2(1.5f, 1f), new Vector2(0.7f, 1.15f), new Vector2(1f, 0.8f), new Vector2(0.5f, 1.1f) ); estuaries.AddTriangleUV2( new Vector2(0.5f, 1.1f), new Vector2(1f, 0.8f), new Vector2(0f, 0.8f) ); estuaries.AddQuadUV2( new Vector2(0.5f, 1.1f), new Vector2(0.3f, 1.15f), new Vector2(0f, 0.8f), new Vector2(-0.5f, 1f) ); } else { estuaries.AddQuadUV2( new Vector2(-0.5f, -0.3f), new Vector2(0.3f, -0.35f), new Vector2(0f, 0f), new Vector2(0.5f, -0.3f) ); estuaries.AddTriangleUV2( new Vector2(0.5f, -0.3f), new Vector2(0f, 0f), new Vector2(1f, 0f) ); estuaries.AddQuadUV2( new Vector2(0.5f, -0.3f), new Vector2(0.7f, -0.35f), new Vector2(1f, 0f), new Vector2(1.5f, -0.2f) ); } }
void TriangulateWaterShore(HexDirection direction, HexCell cell, HexCell neighbor, Vector3 center) { EdgeVertices e1 = new EdgeVertices( center + HexMetrics.GetFirstWaterCorner(direction), center + HexMetrics.GetSecondWaterCorner(direction)); water.AddTriangle(center, e1.v1, e1.v2); water.AddTriangle(center, e1.v2, e1.v3); water.AddTriangle(center, e1.v3, e1.v4); water.AddTriangle(center, e1.v4, e1.v5); Vector3 indices; indices.x = indices.z = cell.Index; indices.y = neighbor.Index; for (int i = 0; i < 4; i++) { water.AddTriangleCellData(indices, weights1); } Vector3 center2 = neighbor.Position; center2.y = center.y; EdgeVertices e2 = new EdgeVertices( center2 + HexMetrics.GetSecondSolidCorner(direction.Opposite()), center2 + HexMetrics.GetFirstSolidCorner(direction.Opposite())); if (cell.HasRiverThroughEdge(direction)) { TriangulateEstuary(e1, e2, cell.IncomingRiver == direction, indices); } else { waterShore.AddQuad(e1.v1, e1.v2, e2.v1, e2.v2); waterShore.AddQuad(e1.v2, e1.v3, e2.v2, e2.v3); waterShore.AddQuad(e1.v3, e1.v4, e2.v3, e2.v4); waterShore.AddQuad(e1.v4, e1.v5, e2.v4, e2.v5); waterShore.AddQuadUV(0f, 0f, 0f, 1f); waterShore.AddQuadUV(0f, 0f, 0f, 1f); waterShore.AddQuadUV(0f, 0f, 0f, 1f); waterShore.AddQuadUV(0f, 0f, 0f, 1f); for (int i = 0; i < 4; i++) { waterShore.AddQuadCellData(indices, weights1, weights2); } } HexCell nextNeighbor = cell.GetNeighbor(direction.Next()); if (nextNeighbor != null) { Vector3 v3 = nextNeighbor.Position + (nextNeighbor.IsUnderWater ? HexMetrics.GetFirstWaterCorner(direction.Previous()) : HexMetrics.GetFirstSolidCorner(direction.Previous())); v3.y = center.y; waterShore.AddTriangle(e1.v5, e2.v5, v3); waterShore.AddTriangleUV( new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, nextNeighbor.IsUnderWater ? 0f : 1f) ); indices.z = nextNeighbor.Index; waterShore.AddTriangleCellData(indices, weights1, weights2, weights3); } }