在上一章中,我们创建了Slope-Cliff三角形连接区域的方法。在这里要注意,Slope-Cliff类型与SSF
类型不同,因为我们不知道的left和right地图单元之间,高度差是等于1还是大于1的,但是我们能确定的一点是left与bottom地图单元之间的高度差为1。根据下图我们发现,不论right的高度如何变化,三角形连接区域的一条边始终是需要进行阶梯化的。所以我们就将Slope-Cliff的三角形连接区域分为两部分进行构建。这里先从一定会阶梯化的底部开始。
对这部分进行构建,也有两种情况。第一种如下图所示,三角形的其中一条边与阶梯部分相连,被分成若干段。这条边上分段的顶点与三角形的另一个顶点相连,这样就完成了三角剖分。但是这样的构建方法会让三角形连接区域中,视觉效果比较差,例如三角形连接区域中,分段相同,但是一条边上断电稀疏,但是越靠近三角形的一个角的时候越密集。而且在之后进行上半段构建的时候,这个情况会被放大。
那么解决这个问题的方法,就是在三角形的一条边上取一个点,所有阶梯化的端点,够与这个点相连接,这样既将三角形连接区域分为了两部分,又不会出现顶点向一处汇聚,显得太过拥挤。
既然找出了一个比较合理的解决方案,那么我们就需要知道三角形上的这个点的具体位置怎么得出。这里是使用了bottom和right两个地图单元的高度差进行插值得到的。也就是最低的地图单元和最高的地图单元之间的高度差,在进行插值,计算出三角形上这个点及其对应的颜色。代码如下:
HexMesh.cs1 2 3 4 5 6 7 8 9 10 11 12 13
| private void TriangulateCornerTerracesCliff( Vector3 begin, HexCell beginCell, Vector3 left, HexCell leftCell, Vector3 right, HexCell rightCell) { float b = 1f / (rightCell.Elevation - beginCell.Elevation); Vector3 boundary = Vector3.Lerp(begin, right, b); Color boundaryColor = Color.Lerp(beginCell.color, rightCell.color, b); }
|
计算出了三角形连接区域边上一点,那么我们来构建一个三角形,观察一下这个点是否正确。代码如下:
HexMesh.cs1 2 3 4 5 6 7 8 9 10 11
| private void TriangulateCornerTerracesCliff( Vector3 begin, HexCell beginCell, Vector3 left, HexCell leftCell, Vector3 right, HexCell rightCell) { … AddTriangle(begin, left, boundary); AddTriangleColor(beginCell.color, leftCell.color, boundaryColor); }
|
我们确定了三角形连接区域边上一点没有问题,那么接下来就要构建这个区域了。与之前构建SSF
三角形连接区域类似,首先构建起始的一个三角面片。代码如下:
HexMesh.cs1 2 3 4 5 6 7 8 9 10 11 12 13 14
| private void TriangulateCornerTerracesCliff( Vector3 begin, HexCell beginCell, Vector3 left, HexCell leftCell, Vector3 right, HexCell rightCell) { … Vector3 v2 = HexMetrics.TerraceLerp(begin, left, 1); Color c2 = HexMetrics.TerraceLerp(beginCell.color, leftCell.color, 1);
AddTriangle(begin, v2, boundary); AddTriangleColor(beginCell.color, c2, boundaryColor); }
|
然后直接将剩余的区域直接构建为一个三角面片。代码如下:
HexMesh.cs1 2 3 4 5 6 7 8 9 10 11
| private void TriangulateCornerTerracesCliff( Vector3 begin, HexCell beginCell, Vector3 left, HexCell leftCell, Vector3 right, HexCell rightCell) { … AddTriangle(v2, left, boundary); AddTriangleColor(c2, leftCell.color, boundaryColor); }
|
接着我们循环构建中间部分的三角面片,代码如下:
HexMesh.cs1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| private void TriangulateCornerTerracesCliff( Vector3 begin, HexCell beginCell, Vector3 left, HexCell leftCell, Vector3 right, HexCell rightCell) { … for (int i = 2; i < HexMetrics.terraceSteps; i++) { Vector3 v1 = v2; Color c1 = c2; v2 = HexMetrics.TerraceLerp(begin, left, i); c2 = HexMetrics.TerraceLerp(beginCell.color, leftCell.color, i); AddTriangle(v1, v2, boundary); AddTriangleColor(c1, c2, boundaryColor); } AddTriangle(v2, left, boundary); AddTriangleColor(c2, leftCell.color, boundaryColor); }
|
这样,我们在三角形连接区域的一条边上,通过插值计算出了一个点,利用这个点将三角形连接区域拆分成了两个部分。并完成了三角形连接区域底部的构建工作。在下一章中,我们将完成顶部的构建。
为什么底部不能像SSF
那样使用阶梯的方式构建,而使用三角形进行构建?
如果我们对这部分区域进行类似SSF
那种阶梯状方式构建,而不是三角面片构建。这就需要分析计算得出的插值点。因为插值点是跟bottom与right的高度差有关,而两者的高度差并不固定,所以这可能导致每个阶梯的四边形,并不在一个平坦的平面上,也就是说一个四边形左右两侧的斜率不同,这样不仅看起来四边形会被拉伸,而且市局效果会很乱。
Github代码