程序化生成水面Mesh工具:湖面
编辑器:
实现思路
湖面Mesh的生成比较简单,主要是编辑器下创建一些小球作为Mesh顶点,通过拖动小球达到编辑顶点位置的功能。
划分三角形
然后对创建出来的小球顶点划分一下三角面,这里主要涉及一个凸多边形和凹多边形的划分,凸多边形的划分比较简单,对顶点做一个顺时针排序,然后可以把所有三角面连到其中一个顶点上,或取首尾顶点连城像拉链一样的锯齿状。对凹多边形的三角划分,我从网上查找了一些现成方案:
感谢作者:https://www.cnblogs.com/lan-yt/p/9200621.html
大概做法是先将凹多边形划分成凸多边形,再按照凸多边形划分三角形。
计算UV
Mesh的UV值会自动将超过1或小于0的值重新取0或1,所以UV的值是重复的,取顶点包围盒的中心作为0.5,0.5位置,上图编辑器中有一个UVRepeat参数,通过这个参数将UV的x和y轴按照与中心点的距离,等比例计算,从而避免UV拉伸的情况,并且能够实现UV的一个缩放效果。
uvs[i] = new Vector2(0.5f + (vertices[i].x - center.x) / m_UVRepeat, 0.5f + (vertices[i].z - center.z) / m_UVRepeat);
UVRepeat取10的时候:
UVRepeat取20的时候:
关于编辑器用法
菜单栏或Hierarchy下点击打开编辑器。
关于参数:
LakeMesh:当前正在编辑Lake对象,不能通过Hierarchy拖拽修改,只能通过编辑器上的按钮选择编辑对象。
Mesh:当前正在编辑的Mesh对象,与LakeMesh对象绑定。
MeshName:Mesh的名字,保存的时候会作为文件默认名。
LockYaxis:Y轴锁定开关,默认Y轴锁定不可编辑,因为湖面一般来说应该是在同水平面的,需要编辑的时候可以去掉勾选。
ShowGizmos:显示一个网格连线的Gizmos。
CheckUV:替换当前材质球为一个查看UV的材质球。
MeshGridColor:修改Gizmos网格线的颜色。
UseRepeatUV:默认使用Repeat的UV,并通过UVRepeat的值来调节。
VerticeScale:调节顶点小球的缩放值,方便编辑用。
按钮:
RebuildMesh,按照当前编辑器参数重建Mesh,有时候通过Inspector面板修改了顶点位置,通过点击这个按钮刷新一下。
ChooseAndEditor:选中一个Mesh对象点击,将其作为编辑对象,并根据其顶点数据创建对应的顶点小球。
ChooseAllPoints:选中所有顶点小球,方便调整整体Mesh位置。
NewLake:移除当前编辑的Lake对象,然后Shift+右键 将会重新创建一个Lake对象。
DeleteVertivce:由于我没找到编辑器下监听删除GameObject的方法,所以就加了一个按钮用来删除顶点小球,选中要删除的小球,点击按钮或Shift+D 删除。
SetToBoundsCenter:将Mesh包围盒的中心点归位到Lake对象的0,0点,方便对位置。
SaveLake:弹出一个文件保存弹窗,保存Mesh文件。
操作:
打开编辑器后,在Scene场景中 通过Shift+右键,创建一个新的Lake对象,有了Lake对象之后 Shift+右键创建可拖动的小球,用于编辑顶点位置。
Shift+D 用于删除小球顶点,可以选中多个小球再删除。
编辑Mesh对象的时候会额外创建一些辅助对象:
绿色的小球和Cube是用Gizmo画的,代表Mesh包围盒的左下角和右上角。
白色圆柱表示Lake对象的0,0点,白色Cube表示Mesh包围盒的中心点,白色胶囊体表示所有顶点小球的重心位置,小球的顺时针排序会依赖这个计算。
其它白色小球用来编辑拖动Mesh顶点。
所有这些生成的辅助对象都被标记为HideFlags DontSave,不会随场景文件保存,当点击运行,关闭场景或关闭编辑器的时候会丢失这些对象,之后需要重新编辑的时候可以通过编辑器上的ChooseAndEditor按钮重新选中Lake对象并编辑。
Vector3 size = m_Mesh.bounds.size;
float _uvRela = size.x > size.z ? size.x : size.z;
for(int i=0; i < count; i++)
{
//uvs[i] = new Vector2((vertices[i].x - min.x) / size.x, (vertices[i].z - min.z) / size.z);
uvs[i] = new Vector2(0.5f + (vertices[i].x - center.x) / m_UVRepeat, 0.5f + (vertices[i].z - center.z) / m_UVRepeat);
uv2s[i] = new Vector2(0.5f + (vertices[i].x - center.x) / _uvRela, 0.5f + (vertices[i].z - center.z) / _uvRela);
}
if(m_UseRepeatUV)
{
m_Mesh.uv = uvs;
m_Mesh.uv2 = uv2s;
}
else
{
m_Mesh.uv = uv2s;
m_Mesh.uv2 = uvs;
}
啊,后面应美术要求多算了一套不依赖UVRepeat的UV,也就是将UV按照01边界展平,不重复,放在UV2里,可以通过UseRepeatUV开关控制。
挂一个Demo:
https://github.com/mutou1994/LakeRiverMeshTools