路网的程序式生成前人曾经提出过多种方式,比如用模板,用L-System,用代理(Agent-Based),用张量场(Tensor Field)。其中比较实用的是L系统和张量场,前者也就是CityEngine中使用的方式。[Parish and Muller, 2001]这里的L系统不是传统的字符串替换的L系统,虽然思想一致,用递归替换的方式替换衍生,但在Extended L系统中,可替换的可以是复杂的带变量的函数,而不仅仅是简单的Turtle移动了。这我们后面再说,这里主要讲张量场的实现[Chen, 2008]
基本思路是:
根据地形生成张量场,可以多个张量场叠加
根据张量场生成道路
张量定义是
它可以有两个互相垂直的本征向量,这个特性很好,因为很多路网交叉口是垂直的。
1张量场生成
可以有多种,比如格网的,轴向的。延海岸线和河流线可以有顺应边缘的张量场,沿高度图也可以有顺应梯度的张量场。这个是一个轴向的这个是高度场的这个是沿水域边界的上面三种张量场可以叠加混合起来之后呢这些张量场甚至还可以加噪声
2主干路生成
从一些随机点开始沿主本征向量方向走,隔一段距离布一个种子点,直到走不下去;按一定规则选一个种子点开始按次本征向量方向移动,布种子点直到走不动;继续选种子点,换方向,布种子点。
当还有种子点,循环: 选取优先级最高的种子点 直到走不动,循环: 沿某个本征向量方向移动 隔一定距离布种子点 切换到另一个本征向量方向单个流线移动策略:就跟着本征向量走就好了,退出条件:1. 出边界了 2. 到了退化点 3. 回到起点了 4. 超出最大长度 5. 离另一个流线太近了,如果这样就往前找一找看能不能接上种子优先度策略:到水的距离,到退化点的距离,到城市中心的距离,几个距离按负幂指数加起来作为评价函数。种子是放优先队列里的。基本思路还是比较简单的,在houdini里实现总比撸C++容易多了,优势是自带点云方法查询最近点比较快,另外自带volumesample, volumegradient功能。缺点是Vex里很难搞高级数据结构,比如想用个priority queue就不支持stl::queue,用sort sop节点倒是还比较方便。另一个愚蠢的事情是Vex是多线程的,虽然不会有数据访问的冲突问题,但改点attribute得全部执行完才能看到,于是就不可能一大段一大段地写Vex,只能分成好多wrangler。
这个张量场的方式相比L系统灵活度更高,想要随机的给个noise的张量场就好了,想贴近地形就给个高度图的,沿岸线的张量场。而L系统基本只有三类:向心的,格网的和有机的。不过L系统在划分Lots看上去更合理,这个以后再说了。