4-13 修复CSS和SCS连接类型的破面

  在上一章中,我们完成了细分后阶梯连接区域的构建。当我们改变地图单元高度的时候,会发现Cliff与Slope类型之间的三角形连接区域,依然会有破面的问题这也是我们之前一直搁置的一个问题。在这一章中,我们先解决cliff-slope-slope (CSS)slope-cliff-slope (SCS)两种连接类型种产生破面的问题。

  产生破面的问题是因为分界点(阶梯连接收束到陡峭面边缘的顶点)的计算受到了干扰。这意味着它不是精确的处于陡峭面的边缘线上,所以就产生了一个裂缝。解决方案是不要对分界点应用噪声扰动,就是说我们需要能选择一个点是否应用扰动。最简单的办法是在HexMesh.cs中添加一个完全不对顶点进行扰动的AddTriangle方法。代码如下:

HexMesh.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class HexMesh : MonoBehaviour
{
/// <summary>
/// 添加单个三角面片的顶点位置信息和索引,顶点不扰动!
/// </summary>
/// <param name="v1">顺时针 第一个顶点的Vector3</param>
/// <param name="v2">顺时针 第二个顶点的Vector3</param>
/// <param name="v3">顺时针 第三个顶点的Vector3</param>
private void AddTriangleUnperturbed(Vector3 v1, Vector3 v2, Vector3 v3)
{
int vertexIndex = vertices.Count;
vertices.Add(v1);
vertices.Add(v2);
vertices.Add(v3);
triangles.Add(vertexIndex);
triangles.Add(vertexIndex + 1);
triangles.Add(vertexIndex + 2);
}


}

  修改TriangulateBoundaryTriangle方法中的语句,在使用边界点构建三角面片时,边界点不在进行扰动。代码如下:

HexMesh.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private void TriangulateBoundaryTriangle(
Vector3 begin, HexCell beginCell,
Vector3 left, HexCell leftCell,
Vector3 boundary, Color boundaryColor)
{
Vector3 v2 = HexMetrics.TerraceLerp(begin, left, 1);
Color c2 = HexMetrics.TerraceLerp(beginCell.color, leftCell.color, 1);

//这里收束到边界点的时候,边界点不再进行扰动
AddTriangleUnperturbed(Perturb(begin), Perturb(v2), boundary);
AddTriangleColor(beginCell.color, c2, boundaryColor);

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);

//这里收束到边界点的时候,边界点不再进行扰动
AddTriangleUnperturbed(Perturb(v1), Perturb(v2), boundary);
AddTriangleColor(c1, c2, boundaryColor);
}


//这里收束到边界点的时候,边界点不再进行扰动
AddTriangleUnperturbed(Perturb(v2), Perturb(left), boundary);
AddTriangleColor(c2, leftCell.color, boundaryColor);
}

  仔细观察TriangulateBoundaryTriangle方法可以发现,我们并没没有用v2去计算其他点的位置。所以在这里我们可以直接先对v2进行扰动,这样就简化了之后调用v2的代码了。代码如下:

HexMesh.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private void TriangulateBoundaryTriangle(
Vector3 begin, HexCell beginCell,
Vector3 left, HexCell leftCell,
Vector3 boundary, Color boundaryColor)
{
//由于在此方法中,并没有用v2继续计算其他顶点,所以在这里先对v2进行扰动,之后代码中直接使用
Vector3 v2 = Perturb(HexMetrics.TerraceLerp(begin, left, 1));
Color c2 = HexMetrics.TerraceLerp(beginCell.color, leftCell.color, 1);

//这里收束到边界点的时候,边界点不再进行扰动
AddTriangleUnperturbed(Perturb(begin), Perturb(v2), boundary);
AddTriangleColor(beginCell.color, c2, boundaryColor);

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);

//使用扰动后的v2点
AddTriangleUnperturbed(Perturb(begin), v2, boundary);
AddTriangleColor(c1, c2, boundaryColor);
}


//使用扰动后的v2点
AddTriangleUnperturbed(v2, Perturb(left), boundary);
AddTriangleColor(c2, leftCell.color, boundaryColor);
}

  现在看起来好多了,但还是会有一些问题。在TriangulateCornerTerracesCliff方法里,分界点的位置是通过左右的坐标点插值计算得到的,但这两个点没有应用扰动。要让边界点能精确吻合陡峭斜坡边缘,需要插值去计算两个扰动过的坐标点来求得边界点。代码如下:

HexMesh.cs
1
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)
{


//这里使用扰动后的坐标点计算分界点
Vector3 boundary = Vector3.Lerp(Perturb(begin), Perturb(right), b);

}

  在TriangulateCornerCliffTerraces方法中也是同理,代码如下:

HexMesh.cs
1
2
3
4
5
6
7
8
9
10
11
private void TriangulateCornerCliffTerraces(
Vector3 begin, HexCell beginCell,
Vector3 left, HexCell leftCell,
Vector3 right, HexCell rightCell)
{


//这里使用扰动后的坐标点计算分界点
Vector3 boundary = Vector3.Lerp(Perturb(begin), Perturb(right), b);

}

  这样我们就修复了cliff-slope-slope(CSS)slope-cliff-slope(SCS)两种连接类型种产生破面的问题。在接下来的章节中,我们来解决cliff-cliff-slope连接类型种破面的问题。

Github代码