解决地形生成各方块边界法线不统一的问题

如图所示,未处理边界法线的效果,法线不统一生成类似分界线的效果,需要统一相邻方块边界相接处的法线。

处理过后效果如图所示:

假设地图为4x4的方格,每格的分段为3(每条边4个顶点)

(a).为地图四角的小格的某些参考顶点赋值

if (size_z >= 2)
{
mapdata[0, 0].normals[ul] += mapdata[0, 1].normals[bl];//左下小格提供其左上和左下的点做参考,之所以是2个,是按照数组遍历顺序
mapdata[size_x - 1, 0].normals[ur] += mapdata[size_x - 1, 1].normals[br];//右下小格提供右上的点
}
if (size_x >= 2)
{
mapdata[0, 0].normals[br] += mapdata[1, 0].normals[bl];
mapdata[0, size_z - 1].normals[ur] += mapdata[1, size_z - 1].normals[ul];//左上小格提供右上的点
}

根据这些格子的参考顶点向上,向右延伸

 1  for (int i = 0; i < size_z; i++)
 2             for (int j = 0; j < size_x; j++)
 3             {
 4                 if (i == 0 && j > 0)//下面一行
 5                 {
 6                     if (j < size_x - 1)
 7                         mapdata[j, i].normals[br] += mapdata[j + 1, i].normals[bl];//右下
 8 
 9                     mapdata[j, i].normals[bl] = mapdata[j - 1, i].normals[br];//左下
10                 }
11 
12                 if (j == 0 && i > 0)//左面一行
13                 {
14                     if (i < size_z - 1)
15                         mapdata[j, i].normals[ul] += mapdata[j, i + 1].normals[bl];//左上
16 
17                     mapdata[j, i].normals[bl] = mapdata[j, i - 1].normals[ul];//左下
18                 }
19 
20                 if (j == size_x - 1 && i > 0)//右面一行
21                 {
22                     if (i < size_z - 1)
23                         mapdata[j, i].normals[ur] += mapdata[j, i + 1].normals[br];//右上
24                     mapdata[j, i].normals[br] = mapdata[j, i - 1].normals[ur];//右下
25                 }
26 
27                 if (i == size_z - 1 && j > 0)//上面一行
28                 {
29                     if (j < size_x - 1)
30                         mapdata[j, i].normals[ur] += mapdata[j + 1, i].normals[ul];//右上
31                     mapdata[j, i].normals[ul] += mapdata[j - 1, i].normals[ur];//左上
32                 }
33 }
34 }
边界最外侧顶点延伸

 (b).为空余的中间部分各小格边角顶点法线赋值

如图所示,依次赋值。

 1 for (int i = 0; i < size_z; i++)
 2  for (int j = 0; j < size_x; j++){
3   if (j < size_x - 1 && i < size_z - 1)//右上角赋值,作为底下其他赋值的基础 4   mapdata[j, i].normals[ur] = (mapdata[j, i].normals[ur] + mapdata[j + 1, i].normals[ul] + mapdata[j, i + 1].normals[br] + mapdata[j + 1, i + 1].normals[bl]).normalized;//四个三角面的法线向量归一化 5   if (j >=1 && i >=1)//左下角赋值,取前,必须按照数组顺序来初始化 6   mapdata[j, i].normals[bl] = mapdata[j - 1, i - 1].normals[ur]; 7   if (j < size_x - 1 && i >=1)//右下角赋值,取前一行 8   mapdata[j, i].normals[br] = mapdata[j, i - 1].normals[ur]; 9   if (j >=1 && i < size_z - 1)//左上角赋值,取前一个 10   mapdata[j, i].normals[ul] = mapdata[j - 1, i].normals[ur]; 11 }

(c).初始化每格非四角处的顶点。数组的遍历顺序是从左往右,从底部往上,边界的各对应方向的顶点等于原值

若AB左右相邻:A格的右法线=A格右法线+B格左法线,B格左法线=A格右法线(已初始化)

若AB下上相接:A格的上法线=A格上法线+B格下法线,B格下法线=A格上法线(已初始化)

代码如下:

 1 for (int i = 0; i < size_z; i++)
 2   for (int j = 0; j < size_x; j++)
 3 {
 4     for (int m = 1; m < cell_segment; m++)//cell_segment是分段数,边上顶点数为cell_segment+1,这里实际是边上顶点数-1
 5     {
 6        up = ((cell_segment + 1) * (cell_segment) + m);
 7        bottom = m;
 8        left = m * (cell_segment + 1);
 9        right = (m + 1) * (cell_segment + 1) - 1;
10 
11        mapdata[j, i].normals[left] = j - 1 < 0 ? mapdata[j, i].normals[left] : mapdata[j - 1, i].normals[right].normalized;//
12        mapdata[j, i].normals[bottom] = i - 1 < 0 ? mapdata[j, i].normals[bottom] : mapdata[j, i - 1].normals[up].normalized;//
13        mapdata[j, i].normals[right] = j + 1 >= size_x ? mapdata[j, i].normals[right] : (mapdata[j, i].normals[right] + mapdata[j + 1, i].normals[left]).normalized;//
14         mapdata[j, i].normals[up] = i + 1 >= size_z ? mapdata[j, i].normals[up] : (mapdata[j, i].normals[up] + mapdata[j, i + 1].normals[bottom]).normalized;//
15     }
16 }

经历a,b,c步骤,所有格子的边界法线统一,以下是函数完整代码:

 1 public void SetNormals()
 2     {
 3         int size_x = Mathf.FloorToInt((float)terrain_size.x / cell_size);
 4         int size_z = Mathf.FloorToInt((float)terrain_size.y / cell_size);
 5         int bl, br, ul, ur;//左下,右下,左上,右上
 6         int up, bottom, right, left;
 7 
 8         bl = 0;
 9         br = cell_segment;
10         ul = (cell_segment + 1) * (cell_segment);
11         ur = (cell_segment + 1) * (cell_segment + 1) - 1;
12 
13         if (size_z >= 2)
14         {
15             mapdata[0, 0].normals[ul] += mapdata[0, 1].normals[bl];//左下小格提供其左上和左下的点做参考,之所以是2个,是按照数组遍历顺序
16             mapdata[size_x - 1, 0].normals[ur] += mapdata[size_x - 1, 1].normals[br];//右下小格提供右上的点
17         }
18         if (size_x >= 2)
19         {
20             mapdata[0, 0].normals[br] += mapdata[1, 0].normals[bl];
21             mapdata[0, size_z - 1].normals[ur] += mapdata[1, size_z - 1].normals[ul];//左上小格提供右上的点
22         }
23 
24         for (int i = 0; i < size_z; i++)
25             for (int j = 0; j < size_x; j++)
26             {
27                 if (i == 0 && j > 0)//下面一行
28                 {
29                     if (j < size_x - 1)
30                         mapdata[j, i].normals[br] += mapdata[j + 1, i].normals[bl];//右下
31 
32                     mapdata[j, i].normals[bl] = mapdata[j - 1, i].normals[br];//左下
33                 }
34 
35                 if (j == 0 && i > 0)//左面一行
36                 {
37                     if (i < size_z - 1)
38                         mapdata[j, i].normals[ul] += mapdata[j, i + 1].normals[bl];//左上
39 
40                     mapdata[j, i].normals[bl] = mapdata[j, i - 1].normals[ul];//左下
41                 }
42 
43                 if (j == size_x - 1 && i > 0)//右面一行
44                 {
45                     if (i < size_z - 1)
46                         mapdata[j, i].normals[ur] += mapdata[j, i + 1].normals[br];//右上
47                     mapdata[j, i].normals[br] = mapdata[j, i - 1].normals[ur];//右下
48                 }
49 
50                 if (i == size_z - 1 && j > 0)//上面一行
51                 {
52                     if (j < size_x - 1)
53                         mapdata[j, i].normals[ur] += mapdata[j + 1, i].normals[ul];//右上
54                     mapdata[j, i].normals[ul] += mapdata[j - 1, i].normals[ur];//左上
55                 }
56 
57                 if (j < size_x - 1 && i < size_z - 1)//右上角赋值,作为底下其他赋值的基础
58                     mapdata[j, i].normals[ur] = (mapdata[j, i].normals[ur] + mapdata[j + 1, i].normals[ul] + mapdata[j, i + 1].normals[br] + mapdata[j + 1, i + 1].normals[bl]).normalized;//四个三角面的法线向量归一化
59                 if (j >= 1 && i >= 1)//左下角赋值,取前,必须按照数组顺序来初始化
60                     mapdata[j, i].normals[bl] = mapdata[j - 1, i - 1].normals[ur];
61                 if (j < size_x - 1 && i >= 1)//右下角赋值,取前一行
62                     mapdata[j, i].normals[br] = mapdata[j, i - 1].normals[ur];
63                 if (j >= 1 && i < size_z - 1)//左上角赋值,取前一个
64                     mapdata[j, i].normals[ul] = mapdata[j - 1, i].normals[ur];
65 
66                 for (int m = 1; m < cell_segment; m++)//cell_segment是分段数,边上顶点数为cell_segment+1,这里实际是边上顶点数-1
67                 {
68                     up = ((cell_segment + 1) * (cell_segment) + m);
69                     bottom = m;
70                     left = m * (cell_segment + 1);
71                     right = (m + 1) * (cell_segment + 1) - 1;
72 
73                     mapdata[j, i].normals[left] = j - 1 < 0 ? mapdata[j, i].normals[left] : mapdata[j - 1, i].normals[right].normalized;//
74                     mapdata[j, i].normals[bottom] = i - 1 < 0 ? mapdata[j, i].normals[bottom] : mapdata[j, i - 1].normals[up].normalized;//
75                     mapdata[j, i].normals[right] = j + 1 >= size_x ? mapdata[j, i].normals[right] : (mapdata[j, i].normals[right] + mapdata[j + 1, i].normals[left]).normalized;//
76                     mapdata[j, i].normals[up] = i + 1 >= size_z ? mapdata[j, i].normals[up] : (mapdata[j, i].normals[up] + mapdata[j, i + 1].normals[bottom]).normalized;//
77                 }
78                 mapdata[j, i].ReviseNormals();//将该格法线重新赋值
79             }
80     }
完整函数

 工程文件:http://files.cnblogs.com/files/luxishi/BuildMap_mesh.zip(地图为1x1时有bug,在上面a处已修正)

原文地址:https://www.cnblogs.com/luxishi/p/6518518.html