6-14 河流笔直穿过地图单元的三角剖分
在上一章中,我们将有河流穿过和没河流穿过地地图单元进行了区分,并且创建了一个方法,专门对有河流穿过的地图单元进行构建。在这一章中,我们先分析最简单的情况:河流笔直穿过一个地图单元。并实现这种情况的构建。
要构建一个笔直的河道,就需要把汇聚到地图单元中心的点,延伸成一条与河道宽度相同的直线。通过观察现在的三角剖分可以发现,如果我们只改变当前河流经过的扇形区域,对其进行拉伸或缩放,那其他两侧相邻的扇形区域就一定会产生破面或重面的情况。所以我们不仅要对当前扇形区域内的顶点进行计算,还会涉及到其两侧相邻的扇形区域内的顶点。
之前我们用5个顶点,将地图单元的每一条边分城了4等份,河道宽度为二分之一边长。而且通过之前的章节我们已经知道,地图单元的外接圆直径与边长相等。如果要实现河流在地图单元中心也保持这个宽度,那么需要将其两侧的扇形区域中,之前的顶点与地图单元重点重合,现在要变为距中心点四分之一距离处。左右两个各四分之一外接圆半径长度,两个组成二分之一外接圆半径长度,刚好跟河道宽度相同。代码如下:
1 | private void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) |
我们计算出了两个新的顶点坐标,根据这两个坐标,使用EdgeVertices
结构体来计算其余3个顶点的坐标,并将它们全都保存下来。代码如下:
1 | private void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) |
接着,我们修改中间顶点的高度,使其下降成为河道。代码如下:
1 | private void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) |
然后,我们先使用TriangulateEdgeStrip
方法来构建连接区域。代码如下:
1 | private void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) |
我们观察构建的结果,发现好像河道还是向内压缩了。河道左右两边的顶点还是在向中间靠拢。结合下图、运行效果与TriangulateEdgeStrip
方法来看。我们理想中的构建方式,应该是河道宽度保持不变,而河道左右两侧的平面,越接近中心位置就越窄。也就是下图中所表示的情况。而我们现在因为使用了TriangulateEdgeStrip
方法来计算中间的三个顶点。导致这五个顶点是等距分布在梯形的中位线上的,结果也就是上图运行效果的样子。
所以在这里,我们需要重载TriangulateEdgeStrip
方法,使其按照新的方式来计算梯形中位线上的5个顶点。代码如下:
1 | public struct EdgeVertices |
现在,我们就可以回到构建河道连接区域的方法中,调用TriangulateEdgeStrip
方法的重载。这里要注意我们计算梯形区域中位线上五个顶点的位置中间顶点,及其两侧的顶点计算方式不变,因为河道的宽度不变。主要是最外侧两个顶点的位置需要重新计算。这里观察上图我们发现,中位线是底边长度的四分之三,也就是外径长度的四分之三。而两侧顶点各偏移了八分之一外径长,也就是六分之一的中位线长。代码如下:
1 | private void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) |
这样,梯形区域的一部分就已经可以正常的构建出来了。如下图:
接下来我们将构建剩下的部分。梯形的顶边上只有三个顶点,无法用之前的方法进行顶点计算。这里我们手动添加顶点进行构建。首先创建河道两侧的三角形面片。代码如下:
1 | private void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) |
通过观察运行结果,河道两边的三角形区域正确构建了出来。接下来构建中间河道的四边形部分。代码如下:
1 | private void TriangulateWithRiver(HexDirection direction, HexCell cell, Vector3 center, EdgeVertices e) |
我们之前没有使用一个颜色值作为参数构建四边形区域的方法,这里我们重载AddQuadColor
方法。代码如下:
1 | public class HexMesh : MonoBehaviour |
至此,我们就完成了集中河流组合中最简单的一种:河流笔直穿过一个地图单元,这种情况下的地图单元构建。接下来的章节中,我们先来分析河流起点和终点应该如何进行三角构建,并实现。