Mandelbrot Set - 在复平面上绘制曼德博集合

曼德博集合(Mandelbrot set,或译为曼德布洛特复数集合)是一种在复平面上组成分形的点的集合,以数学家本华·曼德博的名字命名。曼德博集合与朱利亚集合有些相似的地方,例如使用相同的复二次多项式来进行迭代。(维基百科)

其中的迭代公式:

1
f(Zn+1)=Zn^2+c

其中,c是任意复数。我们知道c可以表示为:c=x+y*i。根据复数的定义,i^2=-1。因此,我们通过将二维平面当作复平面,x是其中复数的实部R,y是复数的虚部Im。根据上面的额迭代公式,使用OpenCL对每个点进行同步的迭代,快速得到曼德博集合。

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
38
39
40
41
42
43
//openCL代码
kernel void Mandelbrot(
global write_only int* result,
int width,//图片宽度
int height,//图片高度
float minReal,//最小实部
float maxReal,//最大实部
float minIma,//最小虚部
float maxIma,//最大虚部
int max_iter)//最大迭代次数,当迭代这么多次后,该复数还没逃逸,则认为其在曼德博集合中
{
//获取GPU当前线程的编号,可以将这个物化为图片当前位置的一个像素点的计算方位
int tX = global_get_id(0);
int tY = global_get_id(1);

//计算坐标的刻度值
float real_inter = (maxReal - minReal) / width;
float ima_inter = (maxIma - minIma) / height;

//当前线程(像素点)在复平面的位置
int cX = minReal + tx * real_inter;
int cY = minIma + (height - tY) * ima_inter;

//迭代
float zX=0;
float zY=0;
int iter=0;
float length_sqr=0;

do
{
iter++;
float temp = zX * zX - zY * zY + cX;
zY = 2 * zX * zY + cY;
zX = temp;

length_sqr=zX * zX + zY * zY;//在GPU上,根号运算要慢得多
}//根据曼德博集合的性质,我们知道集合的中的任意一个复数|z|<2,因此对于复数z=tX+tY*i,|z|^2=tX*tX+tY*tY<4
while(length_sqr < 4 && iter < max_iter);

int loc = tY * width + tX;
result[loc] = iter;//通过迭代值来标识当前位置的像素点是否属于曼德博集合
}

这种每个点都可以独立迭代运算,互不干扰的特性,最适合用GPU来进行计算的了,因此,通过OpenCL,我们可以快速得到想要的数据。使用 Surface Book 的内置显卡nVidia 520计算3000*3000规模,迭代512次的数据,可以在30ms内完成。如下是通过得到的数据生成的一些配色图:

复数与曼德罗集合的相关信息,可参考:https://msdn.microsoft.com/zh-cn/library/jj635753(v=vs.85).aspx

评论