路网的程序式生成前人曾经提出过多种方式,比如用模板,用L-System,用代理(Agent-Based),用张量场(Tensor Field)。其中比较实用的是L系统和张量场,前者也就是CityEngine中使用的方式。[Parish and Muller, 2001]这里的L系统不是传统的字符串替换的L系统,虽然思想一致,用递归替换的方式替换衍生,但在Extended L系统中,可替换的可以是复杂的带变量的函数,而不仅仅是简单的Turtle移动了。这我们后面再说,这里主要讲张量场的实现[Chen, 2008]


基本思路是:

  1. 根据地形生成张量场,可以多个张量场叠加

  2. 根据张量场生成道路

张量定义是

Houdini中程序式街道生成_java它可以有两个互相垂直的本征向量,这个特性很好,因为很多路网交叉口是垂直的。


1张量场生成


可以有多种,比如格网的,轴向的。延海岸线和河流线可以有顺应边缘的张量场,沿高度图也可以有顺应梯度的张量场。这个是一个轴向的Houdini中程序式街道生成_java_02这个是高度场的Houdini中程序式街道生成_java_03这个是沿水域边界的上面三种张量场可以叠加混合起来Houdini中程序式街道生成_java_04之后呢这些张量场甚至还可以加噪声

Houdini中程序式街道生成_java_05


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看上去更合理,这个以后再说了。