讲道理呢,World Machine的地形用Houdini都是可以做出来的。不过还是有些局限,尝试了一下。
1. 噪声地形
主要就是两类:Voronoi 和 Perlin
Voronoi
Voronoi很简单,VOP里面直接就有Voronoi Noise
出来和World Machine的很像。
Perlin
Perlin可以用Vop 里面的aanoise,不过这里选择了用wrangler写VEX。思路就是很多不同频率的aanoise叠加起来,傅里叶变换嘛。
代码是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
float turb(vector sample_point; float roughness; float lacunarity; int octaves;) { float sum = 0; float weight = 1.0; vector samp_p = sample_point; for (int i=0; i<octaves+1; i++) { // vector noise -0.5 to 0.5 range sum += (noise(samp_p) - 0.5) * weight; // next octave will be scaled in size samp_p *= lacunarity; // and reduced in contribution weight *= roughness; } return sum; } //ref parameters vector offset = {0,0,0}; float scale = chf("scale"); float lacunarity = chf("lacunarity"); float roughness = chf("roughness"); float height_scale = chf("height_scale"); int octaves = 8; vector sp = @P * scale + offset; float cal = turb(sp, roughness, lacunarity, octaves) * height_scale; @P.y += cal; @height = @P.y; |
频率每次乘lacunarity,强度每次乘roughness。
出来效果
perlin 和 voronoi叠加就基本可以得到目标地形的原型了。
2. 变形
World Machine里很多节点,其实用Houdini 一个Ramp Chanel就解决了,比较像GH的Graph Mapper,不过更自由。
效果:
代码也很简单:
之前先promote到detail里了两个参数,高度最大最小值。
1 2 3 4 5 6 7 8 9 |
float h = f@height; float toramp = fit(h, detail(0, "height_min"), detail(0, "height_max"), 0, 1); float remap = chramp("ramp_height", toramp); float mapback = fit(remap, 0, 1, detail(0, "height_min"), detail(0, "height_max")); f@height = mapback; v@P.y = mapback; |
到此,基本意味着World Machine在溶解之前的功能,用Houdini都可以代替。
3. 侵蚀
这部分就比较复杂了,World Machine提供了四种:Hydraulic, Thermal, Snow, Coastal Erosion.
主要试了下Hydraulic,有一些论文参考(Mei, 2007)(Jako, 2011)
Mei Xing(梅星)这篇比较好懂。
插一句,查了下梅星是在中科院自动化所拿的博士,然后在三星研究院工作两年,中科院自动化所当了几年助理教授,现在在Snapchat工作。
总共有五个变量:地面高度b,水位高度d,沉积量s,水流量(vector4 f),沉积移动速度v(相当于高度场梯度)
基本模型分为5步:
1. 降水,增加水位高度
2. 水流动,取决于附近总高度(b+d),以差值计算水流量,以水流量计算速度。
3. 沉积溶解,水流含沙量固定。如果当前含砂容量(capacity)比沉积量(s)大,那么水流溶解一部分土壤,沉积量(s)增加、高度(b)减少。
4. 沉积移动,根据速度方向差值移动沉积量。
5. 水(d)蒸发
Houdini in VEX第八周课程讲的这个,我也强行重写了一遍代码,原作代码有个地方写错了,移动沉积时左右方向应该取v.z,而不是v.y. 另外原作每一步都要重新计算周边点序号,其实直接把周边点序号存一个vector4就成了,速度更快。
但是效果不是非常好。可能是因为分辨率低也可能是算法原因,沟壑都没有出来。
World Machine的作者并没有说过他用的什么算法,不过在WM论坛某个帖子里,他引用过(Jako, 2011)那篇论文。具体实现可能还是有不少差别的,Erosion那个节点有很多参数似乎没法用本文这个Hydraulic Erosion的算法解释。效果也有差异。WM作者也没有发过什么论文,就写出来WM了。
另外用VEX还有速度问题。虽然是多线程作业,不过还是慢,因为没有用GPU。
有帖子说如果要用GPU意味着VEX大部分要重写。不如用Gas OpenCL的一个wrangler。
上面那篇(Jako, 2011)做了一个比较:
基本还是合理的,我的电脑上跑1024的分辨率,每个循环大概500ms(8核 2.6GHz)。所以跟World Machine速度是没法比的。WM做一个1024*1024的erosion,普通的1-2s就跑完了。这里刚跑一个循环啊。
WM很快,难道用了GPU计算?作者似乎也没提过,只是猜测了。
4. 总结
用Houdini代替WorldMachine有几个优点:
- 简化工具链
- 制作地形自由度更强,各种参数都可以自己设定贴图指定。
- asset更容易管理
- 地形可以和其它场景一起生成。
但是也有一些问题:
- 侵蚀算法还需要提升,可能有不少工作要做
- VEX速度太慢,需要用GPU计算。
- 其它侵蚀算法的引入。
参考文献:
Mei, Xing, Philippe Decaudin, and Bao-Gang Hu. “Fast hydraulic erosion simulation and visualization on GPU.” Computer Graphics and Applications, 2007. PG’07. 15th Pacific Conference on. IEEE, 2007.
Tóth, Supervisedby Balázs. “Fast Hydraulic and Thermal Erosion on the GPU.” (2011).
发现了什么了不得的东西