分形应用:造山
一、分形山脉
1、山脉原型:
分形是具有自相似性的图形,即它们都具有最初的原型。如果山脉是分形,那它的原型又是什么?容易想到的是简单的三角形。一个立起的三角形,俨然山的抽象。
2、递归迭代:
那三角形又是如何能一步一步地内部迭代而逼近一座山呢?在1978年,Loren Carpenter 就解决了这个问题。他以简单而机械的方法:递归分割、中点置换,绘制了如下图形。
相关网址:http://www.cnblogs.com/szlongman/archive/2009/07/25/1530993.html
3、准备工作:
使三维立体图形在二维平面上呈现的方法:斜二测画法
建立一个从三维空间向二维空间的映射
x0 = y - x * cos(θ) y0 = x * sin(θ) - z |
4、一种实现:
①在xoy平面取三个点,使之能构成一个三角形;
②第n次迭代,每个三角形的三边中点在z轴方向上平移(max * rnd() * rough^n)个单位,形成新的3个点,新的3点与原来的3点将重新构成4个新的小三角形(max:山的最大高度,rnd():随机函数,返回[-1,1],rough:陡峭程度,取值[0,1]);
③给各个三角形填充颜色,可以根据三角形的重心的高度(三点的竖坐标的平均值),填充不同的颜色。
注:各三角形的公共边的中点应保证只有一次纵移,避免形成的山体破碎。
一、山脉地形
1、另一种想法:
人的视觉感官只能察觉物体的三面,所以实际上山体只须要呈现它的一个面向我们的表面,就足见效果。在这里山体,未有其体,只是一幅实际意义上的地形图。
/**地形接口**/ public interface Terrain { public double getAltitude (double i, double j); public RGB getColor (double i, double j); } public class RGB { private double r, g, b; public RGB (double r, double g, double b) { this.r = r; this.g = g; this.b = b; } public RGB add (RGB rgb) { return new RGB (r + rgb.r, g + rgb.g, b + rgb.b); } public RGB subtract (RGB rgb) { return new RGB (r - rgb.r, g - rgb.g, b - rgb.b); } public RGB scale (double scale) { return new RGB (r * scale, g * scale, b * scale); } private int toInt (double value) { return (value < 0.0) ? 0 : (value > 1.0) ? 255 : (int) (value * 255.0); } public int toRGB () { return (0xff << 24) | (toInt (r) << 16) | (toInt (g) << 8) | toInt (b); } } |
地形图再去掉颜色,仅保留 由横、纵坐标向竖坐标的映射关系,这样抽象而成几何立体图形,就是一张简单曲面。一个简单的方法是:创建一个二维数组,保存该映射关系。由行、列标对应横、纵坐标,数组存储该点处的海拔高度的对应值。
2、然后便是运用算法,为整个数组赋值。
Diamond-Square算法:
i :为方格的四个顶点赋初值;
ii : 第n次执行时,计算该方格四个顶点的平均值+∆X(= rnd() * rough^n),赋予中心点;
iii : 同理以平均值+∆X为剩余的四个中点赋值;
iiii : 分别选取恰被分割成的四个方格,执行ii、iii、iii;
为整个数组赋完值后,再确定一个由海拔到颜色的映射,就可以在画图形了。
public class FractalTerrain implements Terrain { …… public double getAltitude (double i, double j) { …… } private RGB blue = new RGB (0.0, 0.0, 1.0); private RGB green = new RGB (0.0, 1.0, 0.0); private RGB white = new RGB (1.0, 1.0, 1.0); public RGB getColor (double i, double j) { double a = getAltitude (i, j); if (a < .5) return blue.add (green.subtract (blue).scale ((a - 0.0) / 0.5)); else return green.add (white.subtract (green).scale ((a - 0.5) / 0.5)); } }
|
画图可以选择从数组一次取出三点,画三角形,颜色为三角形重心处的对应颜色;或是每次取单点,画出该点;……
为数组赋值的算法可以很自由的替换,甚至各处的颜色可以不直接与海拔相关,而与所处方位(即横、纵坐标)相关。
相关网址:http://www.javaworld.com/article/2076745/learn-java/3d-graphic-java--render-fractal-landscapes.html