1. 前言
最近连续做了很多代码动态生成Mesh的工作,从动态生成修改瞄准范围的Mesh到可破坏的墙壁,以及之前写了一半导航网格生成.
想借此机会整理下最近的积累,如果在阅读过程中发现一些问题或是有争议的地方,欢迎交流
2. Mesh数据简介
一个Mesh的必要结构有: 顶点,三角形
用于渲染的Mesh一般就会有:
UV: 一般会有多组,一般0是主贴图uv,Unity中1是lightmaps使用 2是dynamic GI使用
法线: 处理光照等
颜色: 一般作为额外数据存储
其他数据;
3.创建简单的Mesh
Vector3[] newVertices = {
new Vector3(-0.5f, 0, 0), new Vector3(0.5f, 0, 0),
new Vector3(-0.5f, 0, 1), new Vector3(0.5f, 0, 1)
};
Vector2[] newUV = {
new Vector2(0, 0), new Vector2(1, 0),
new Vector2(0, 1), new Vector2(1, 1)
};
int[] newTriangles = { 0, 2, 1, 2, 3, 1 };
LineMesh = new Mesh();
LineMesh.vertices = newVertices;
LineMesh.uv = newUV;
LineMesh.triangles = newTriangles;
LineMesh.RecalculateBounds();
应用在游戏里:
a. 拖尾,轮胎印
b. 技能瞄准特效
4.格子地图转NavMesh
过程概述:
1 划分区域
这步比较简单,把相连的局域划分再一起就可以了
2 每个范围的边缘点
3 生成全Mesh
将空间内的关键点,边数据,用 Delaunay 德洛内三角划分,该算法比较复杂,但网上有很多实现
一个Unity中的实现: https://github.com/Scrawk/Hull-Delaunay-Voronoi
需要注意的是,有时候划分出来的边,和预想中的边不一致,需要处理一下
4 剔除阻挡内的三角形
5 对比Unity原生的导航网格生成数据
最终结果分析
这里给的过程只是由格子地图数据往导航网格数据转化的一种方法,并不是真正的导航网格生成算法.
缺少了关于半径的处理,多层空间的处理,凸多边形划分等操作
5. 可破坏的墙壁
可破坏的墙壁一般有三种实现方法
1. 将有限种类的砖块按照简单逻辑组合成一面墙,破损时,按砖块掉落
如彩虹6号中的木板墙就是用这种方法做的
2. 将原本的Mesh离线拆分为几块,在破碎时整体爆开
一般的整体可破坏物都是这么做的,比如木栅栏
3. 某个部位被破坏时,实时在Mesh上扣一个洞
把墙壁被破坏的部分当做是阻挡,和之前所讨论的格子地图转导航网格的算法十分类似
4. 有一些额外的数据要处理
a 将2D的Mesh片生成为3D的墙壁
需要将顶点位移复制一份,背面三角形反向,边缘补上侧面
b 显示部分数据,需要额外计算顶点的uv值
c 破碎边缘的处理,参考2D格子地图的边界处理方式,在边缘上铺上一层破碎效果的边