如图所示,未处理边界法线的效果,法线不统一生成类似分界线的效果,需要统一相邻方块边界相接处的法线。
处理过后效果如图所示:
假设地图为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处已修正)