效果展示:
可直接使用的完整代码在本文最后
工具介绍:
- Auto Cutting属性,勾选该属性后,Each Terrain Size属性失效,脚本会根据Terrain Size属性自动划分网格,单个网格大小不会大于256*256.
- Height Map属性用来存放灰度图
- Terrain Height、Terrain Size 用来指定mesh的高度和大小
- 在Auto Cutting属性未勾选的情况下, Each Terrain Size属性可以用来指定每块地图的大小,属性要求必须能被TerrainSize整除
- Terrain Mat规定了地形的材质
- Origin属性为Mesh的父对象,可为空,默认为脚本所在对象
- 勾选Create Prefab属性,会将动态生成的Mesh文件保存为Prefab,在Assets文件夹下
Mesh基础知识:
https://catlikecoding.com/unity/tutorials/procedural-grid/
根据灰度图生成Mesh
在读取图像之前,务必勾选Read/Write Enable属性
单张Mesh的话,我们需要做的只是对它顶点坐标的Y值做一些手脚
vertices.Add(new Vector3(i, HeightMap.GetPixel(X,Y).grayscale * TerrainHeight,j));
HeightMap.GetPixel((int)a,(int)b).grayscale;可以对图像灰度值进行采样
对Mesh进行切割
由于Mesh的限制,单张Mesh大小不能大于256*256,而且,我们通常不会把整个地图全部加载出来,地图分块是必须的
所谓切割,其实就是分批对灰度图采样
vertices.Add(new Vector3(TX*EachTerrainSize+i, HeightMap.GetPixel(X,Y).grayscale * TerrainHeight, TY*EachTerrainSize+j));
需要注意,无论TerrainSize值为多少,整张灰度图都会被利用到,就是说,在采样之前有一个缩放的过程
int X =(int)((float)TX * (float)EachTerrainSize *((float)MapWidth/(float)TerrainSize) + (float)i * ((float)MapWidth / (float)TerrainSize));
int Y = (int)((float)TY * (float)EachTerrainSize *((float)MapHeight / (float)TerrainSize) + (float)j * ((float)MapHeight / (float)TerrainSize));
Mesh切割之后有缝隙问题
这是因为,两个相邻的Mesh中间的连线并没有连接起来
我的做法是,规定255*255为最大单片Mesh大小,剩下的预留,用来补间,排除不需要补间的情况
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
//只有在单片Mesh(不切割)的情况下,EachTerrainSize才有可能==256
int EachTerrainSize_1 = EachTerrainSize == 256 ? 256 : EachTerrainSize + 1;
for (int i = 0; i < EachTerrainSize_1; i++)
{
for (int j = 0; j < EachTerrainSize_1; j++)
{
if (j == EachTerrainSize_1 && TX >= MAXXY-1)
{
break;
}
if (i == EachTerrainSize_1 && TY >= MAXXY - 1)
{
break;
}
int X =(int)((float)TX * (float)EachTerrainSize *((float)MapWidth/(float)TerrainSize) + (float)i * ((float)MapWidth / (float)TerrainSize));
int Y = (int)((float)TY * (float)EachTerrainSize *((float)MapHeight / (float)TerrainSize) + (float)j * ((float)MapHeight / (float)TerrainSize));
vertices.Add(new Vector3(TX*EachTerrainSize+i, HeightMap.GetPixel(X,Y).grayscale * TerrainHeight, TY*EachTerrainSize+j));
if (i == 0 || j == 0) continue;
triangles.Add(EachTerrainSize_1 * i + j);
triangles.Add