程序化生成水面Mesh工具:河流
程序化生成水面Mesh工具:河流
编辑器
实现思路
主要参考了知乎上这位大神的文章
https://zhuanlan.zhihu.com/p/141976251
大概是使用Catmull曲线构建河流的轨迹线,通过拖拽轨迹线关键点小球编辑曲线,然后根据轨迹线按照河流宽度创建Mesh顶点,再将顶点连成三角面,并计算UV。
Catmull曲线可以创建出穿过关键点的曲线,正好适合用来做这种轨迹线,不过这里使用贝塞尔曲线也是可以实现的。
这里主要有一个问题是,因为河道是有宽度的,随意拖拽轨迹线关键点的时候可能会出现转角过大导致河道顶点重叠,造成三角面重叠。针对这个问题我一开始考虑将重叠的顶点合并,但是不能很好的处理一些极端情况,就交叉的情况仍然还是会出现,后来考虑在生成河道顶点的时候,将转弯处的河道顶点做一个渐变插值,相当于把原本垂直于轨迹线的河道两边连线,改成向转弯方向扩散,然后删除掉仍会交叉的顶点,保留拐角处不交叉的顶点,得到一个还不错的效果。
计算UV
UV的计算还是像湖面一样,设置一个UVRepeat值,以河道中心线为0.5,根据河道长度和宽度累计重复计算,并通过UVRepeat控制UV缩放。
_curLength += Vector3.Distance(_resultWayPoints[i - 1], _resultWayPoints[i]);
_curUVRate = _curLength / m_UVRepeat;
if (m_Horizontal)
{
uv.x = _curUVRate;
uv.y = 0.5f - _halfRiverWidth / m_UVRepeat;
}
else
{
uv.x = _halfRiverWidth / m_UVRepeat + 0.5f;
uv.y = _curUVRate;
}
UVRepeat取10:
UVRepeat取20:
关于重复编辑
因为河流Mesh不像湖面可以直接编辑顶点,河流Mesh编辑的是轨迹曲线的关键点,而这些点只在编辑的时候用到,编辑完了之后Mesh上并不会保留这些数据,所以后续想要重新编辑的话,就得要把这些轨迹线数据,包括还有一些河流宽度,流向,精度,网格数等数据全部与Mesh文件对应生成一份配置文件,需要编辑的时候加载这些配置文件,创建编辑需要的关键点,编辑器数据等。
public class RiverCfgJson
{
public bool horizontal = true;
public bool useUVRepeat = false;
public float uvRepeat = 10;
public int perGridNum = 1;
public float smoothNess = 0.01f;
public int smoothAmount = 10;
public Vector3[] wayPoints;
public float[] wayPointsWidth;
}
使用Json文件保存这些配置数据,存储在Editor目录下,由于Unity本身有解析Json的库,所以用起来还比较方便。
此处我另外创建了一份tempRiver.json文件,用于保存当前正在编辑的River数据,因为一般是编辑完成,保存Mesh的时候才会存储一份配置文件,而当前正在编辑的River数据有可能会由于运行,编辑器关闭等原因丢失编辑数据,所以在一些关键操作,拖动轨迹线,修改宽度,精度,网格数等操作的时候,会自动将数据保存到tempRiver.json,可以通过加载这个tempRiver找回当前正在编辑的River。
编辑器使用:
菜单栏或Hierarchy下点击打开编辑器。
关于参数:
一些参数与湖面编辑器相同,就不写了。
Horizontal:控制河流的流向,横向或者纵向
Vertical:河流的流向需要保证Shader里计算的时候是从uv x的0到1 或者 y的0到1, x 0到1则是横向流的,y轴0到1则是纵向流的。
DefaultWidth:河流的默认宽度,每添加一个轨迹曲线关键点,按照这个默认宽度计算出河道两边顶点的位置。
PointWidth:选中曲线上的关键点的时候,可以修改此处河道的宽度,而该点前后关键点之间的宽度通过插值计算。
PerGridNum:控制河道宽度上构成的网格数量,有时候河道转角过大会造成UV拉伸,增加网格数可以使UV更平滑,
SmoothNess:用于曲线上转角角度相差不大的点,减少每两个关键点之间的网格数量,该值越小,精度越高。
SmoothAmount:控制每两个关键点之间的平滑点数量,控制曲线的平滑度。
按钮:
ChooseRiver:选中一个想要编辑的River对象。
LoadTemp:选中一个想要编辑的River对象,并加载tempRiver中的配置,用于找回刚刚编辑的River数据。
LoadConfig:弹出一个文件选择框,加载保存过的配置文件。
SaveConfig:根据MeshName保存一个同名的配置文件到Editor目录,由于这些配置文件只在编辑器下才会用到,所以就写死了存储目录。
操作:
与LakeMesh一样,编辑过程中也会创建一些辅助对象,
这个圆柱表示River对象的000位置。
这些辅助对象与轨迹线上编辑用的小球也都设置为DontSave,编辑过程中可能会丢失这些对象,通过加载tempRiver.json找回重新编辑。
- 上一篇: 程序化生成水面Mesh工具:湖面
- 下一篇: 关于DoTween的一个可视化编辑扩展组件