Unity自带了一个非常强大的地形编辑器,但是总结起来也有一些缺点
1.不能在运行时编辑
2.不能跨多块地图编辑(Unity2018可以实现跨地形编辑)
正好近期的项目中需要在运行状态下实现超大地形和跨多块地形编辑的功能,于是花了一段时间研究了地形的动态编辑。Unity本身虽然无法为我们实现运行时编辑,但是TerrainData类的强大API弥补了这一缺点,从这篇文章开始会逐步构造一个动态修改地形的工具类,实现了地形高度编辑,树木编辑,细节编辑,贴图编辑以及自定义笔刷。后面将分成几篇文章分别讲解,最后会提供源码的下载。这一篇对我们需要处理的地形数据进行介绍。
github工程链接https://github.com/xdedzl/RunTimeTerrainEditor
1.TerrainData
在场景中创建一块地形时,Unity会帮我们自动创建一个TerrainData文件,这个文件展开后会发现有一张含有RGBA四个通道数据的贴图。我们地形数据实际上也就时这张贴图的数据。由于RGBA四个通道的取值范围时[0,1],所以我们在给地形设置高度图,透明通道图等数据时,也都是将其实际值转化为0到1的比例值进行设置。
下面是随便创建的一块地形以及其TerrainData的贴图,由此大致可以猜出RGBA四个通道每一个都代表一种类型的地形数据。
2.HeightMap
Unity的高度图是一个第一维和第二维长度(必须是2的n次方加1,加1是为了连接相邻的地形块)相等的二维数组,取值范围是0到1。用这个值乘上地形的最高高度terrainData.size.y就是这个点在世界空间中的实际高度。高度图的第一维对应世界坐标系中的z轴,第二维对应x轴,这一点与我最开始想的正好相反。Terrain也是一个Mesh网格,二维数组的数据对应的也就是这些网格顶点的高度数据。对Unity动态绘制网格不熟悉的可以自行百度,资料很多,这里我推荐一个国外大神的网站,很多国内资料的“原创”博客都搬运自大神的网站,里面有不少好东西。
3.AlphaMap
在Unity的地形编辑器上,我们在编辑地形贴图的时候,需要在面板上添加贴图,Unity2018之前,这个贴图数据其实是SplatProotype,到Unity2018后官方做了更新,变成了TerrainLayer。在我后面的文章中对这一点做了适配。
TerrainLayer中包含了漫反射贴图、法线贴图等数据,我们在修改地形之前,需要建立一个TerrainLayer的数组并赋值。
AlphaMap是一个三维数组,第三维表示层级,也就是我们需要在初始化中设置的TerrainLayer。AlphaMap第一维和第二维的长度设置为2的n次方,其索引代表的是一个小方块的贴图。三位数组的取值范围一样是0到1,值的含义的是当前层级贴图所占的比例。一个小方块可以设置不同的Layer,Unity会按照你设置的比例自动进行融合。
4.DetailMap
DetailMap在编辑之前也需要初始化一个数组DetailPrototype。
同高度图一样,DetialMap也是一个二维数组,但是它是一个int型的数组,其取值范围也不再是0到1。其值的含义是在索引所对应的小方块上对应草的数量。
5.Tree
上述几个数据的设置都是在TerrainData中进行的,树木的设置移到了Terrain中,并且F12跟踪到Terrain类后并没有发现删除树木的API,后来看了一下Terrain的源码,发现删除树的方法是受保护的,外界无法直接调用,所以我在工具中用了反射,后面的文章会细说这一部分。