Mandelbrot集合及其渲染

article/2025/9/15 20:06:28

什么是Mandelbrot集合?

Mandelbrot集合是在复数平面上组成分形的点的集合,它正是以数学家Mandelbrot命名。

Mandelbrot集合可以用复二次多项式
\[ f_c(z)=z^2+c \]
来定义
其中c是一个复数。对于每一个c,从\(z = 0\),开始对\(f_c(z)\)进行迭代。

序列\((0, f_ c(0), f_c(f_ c(0)), f_ c(f_ c(f_ c(0))), \ldots)\)的元素的模(复数具有模的概念)或者延伸到无穷大,或者只停留在有限半径的圆盘内。Mandelbrot集合就是使以上序列不延伸至无限大的所有c点的集合。
从数学上来讲,Mandelbrot集合是一个复数的集合。一个给定的复数c或者属于Mandelbrot集合M,或者不属于。比如,取c = 1,那么这个序列就是(0, 1, 2, 5, 26, ...),显然它的值会趋于无穷大;而如果取c = i,那么序列就是(0, i, -1+i, -i, -1+i, -i,...),它的值会一直停留在有限半径的圆盘内。

事实上,一个点属于Mandelbrot集合当且仅当它对应的序列(由上面的二项式定义)中的任何元素的模都不大于2。这里的2就是上面提到的“有限半径”。

绘制Mandelbrot集合

可以将屏幕上的一个像素映射为坐标系中的一点,如果该点属于Mandelbrot集合,就将该像素着为黑色,这样逐一对每个像素进行判断和着色,就可以模拟绘制Mandelbrot集合了。

完成映射后来考虑如何判断一个点是否属于该集合。其根据就是上面的结论:一个点属于Mandelbrot集合当且仅当它对应的序列(由上面的二项式定义)中的任何元素的模都不大于2,由于序列的的元素有无穷多个,我们只能取有限的迭代次数来模拟了,比如取100或1000次。

下面的代码shader代码完成了上面的思想。
其中迭代次数为200.
fragCoord.xy传入的当前要计算颜色的像素点的坐标。iResolution.xy是显示区域的宽高。iTime是时间变量。
代码的前面一部分将像素点坐标转换到了逻辑坐标系的坐标,并且随着时间变化对显示区域不断缩放,使得我们可以动态的观察不同大小尺度的Mandellbrot集合。
后面一部分计算了当前点是否位于Mandelbrot集合。

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{vec2 p = -1.0 + 2.0 * fragCoord.xy / iResolution.xy;//[0, 1]p.x *= iResolution.x/iResolution.y;//keep with h/w radio// animation    float tz = 0.5 - 0.5*cos(0.225*iTime);//[0,1]float zoo = pow( 0.5, 13.0*tz );//[1/2^13,1]vec2 c = vec2(-0.05,.6805) + p*zoo;// iteratevec2 z  = vec2(0.0);float m2 = 0.0;int isIn = 1;for( int i=0; i<200; i++ ){if( m2 > 2.0 ) { isIn = 0; break; }// Z -> Z² + c          z = vec2( z.x*z.x - z.y*z.y, 2.0*z.x*z.y ) + c;m2 = dot(z,z);}vec3 col = vec3(isIn==1?0:1 );fragColor = vec4( col, 1.0 );
}

可以进入这个地址观看效果:https://www.shadertoy.com/view/3lsXWH

我们已可以从可视化的效果中观察到数学的美妙,从简单的递归定义中可以得的这种在大小尺度上不断重复的图案。
然而渲染效果不够好,我们观察到很多黑色的散点,和主体并不是连接的,而且在缩放的过程中,这些散点不断忽然消失,又忽然出现。

改进渲染效果

前面一个假设“将屏幕上的一个像素映射为坐标系中的一点”其实是不对,屏幕中的像素是有限的,一个像素点对应的应该是坐标系中一块区域,而不是一个点,然而计算中将像素点映射到了对应区域的中心点,如果这块区域位于Mendelbrot集合分形图形的边缘分支上,它包含了无穷的分形的细节,区域中心点可能刚好位于Mandelbrot集合中也可能刚好位于集合外。所以在分形图形的边缘分支处出现了很多的散点。随着缩放,在细节丰富地方的黑色点出来类似噪声的效果,其实是由于前后两帧像素点对应的区域的中心位置是否在集合中发生了变化。
MandelbrotSetRender_1
如何改进渲染效果呢?应该让像素反映出改点对应区域的密度,而不是仅仅取中心点计算,即如果该区域内有更多比例的点位于集合,使它表现出来的颜色更趋于黑色。
但是如何计算出对应区域的位于集合内的点的比例?想要得到这个精确的数值貌似是个不可能的任务,因为在我们的认知中分形图形并不是一个确定性的图形,它具有无穷的细节。但是我们可以采用某种方法估计这个比例。
假设我们可以得到某一点距离Mandelbrot集合图形边界的最短距离Dist,如果点位于集合内,Dist等于0,如果位于集合外,Dist是一个正值。Dist的计算方法在Inigo Quilez的文章distance rendering for fractals中给出了,在本文中就不具体阐述来了,我们把它当做一个黑盒,假设它的结果是正确的。
如果最短距离大于像素区域的大小,说明没有像素区域内不包含集合中的点,该区域的密度为零;
如果最短距离小于像素区域的大小,可以说明以像素区域中心为中心以最小距离为半径的圆内一定不包含集合点,我们假设剩余的面积都是被集合点充满,然后我们可以根据面积的比例来估计集合点的比例。如下图所示:

MandelbrotSetRender_3
像素区域的宽高分别为w,h,中心点距离集合边缘的距离为D,则区域内密度估计为\(Density = (w*h - Pi*D^2)/(w*h)\)
这个估计值显然会比真实值更大。
当图像缩小时,像素对应的区域会变大,如图中的大的红色框所示,这时的密度估计会变大,在渲染中表现就是随着视口放大,原先有很多细节的地方逐渐缩小,并且变得更黑。
下面是根据上面讨论实现的效果:
观看地址:https://www.shadertoy.com/view/wtlSW8、
MandelbrotSetRender_4
从shaderToy的实时演示和截图中可以看出显示效果得到了很大提高,如果有更好的密度估计方法,显示效率和显示质量还能得到进一步提升。

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{vec2 p = -1.0 + 2.0 * fragCoord.xy / iResolution.xy;p.x *= iResolution.x/iResolution.y;// animation    float tz = 0.5 - 0.5*cos(0.225*iTime);float zoo = pow( 0.5, 13.0*tz );//[1/2^12,1]vec2 c = vec2(-0.05,.6805) + p*zoo;// iteratebool isIn = true;vec2 z  = vec2(0.0);float m2 = 0.0;vec2 dz = vec2(0.0);for( int i=0; i<200; i++ ){if( m2>1024.0 ) { isIn=false; break; }// Z' -> 2·Z·Z' + 1dz = 2.0*vec2(z.x*dz.x-z.y*dz.y, z.x*dz.y + z.y*dz.x) + vec2(1.0,0.0);// Z -> Z² + c          z = vec2( z.x*z.x - z.y*z.y, 2.0*z.x*z.y ) + c;m2 = dot(z,z);}// distance // d(c) = |Z|·log|Z|/|Z'|float d = 0.5*sqrt(dot(z,z)/dot(dz,dz))*log(dot(z,z));if (isIn)d = 0.0;// estimate density in the pixel areavec2 pixelScale = vec2(zoo/iResolution.y*iResolution.x/iResolution.y,zoo/iResolution.y);float pixelArea = pixelScale.x * pixelScale.y;float k = 1.0;float density = clamp((pixelArea - 3.1415926*d*d*k)/pixelArea, 0.0, 1.0);density = pow(density,3.0);             vec3 col = vec3( mix(1.0,0.0,density) );fragColor = vec4( col, 1.0 );
}

其中变量d就是当前像素点代表的区域中心点距离集合边界的距离,其计算原理本文暂且不谈。
vec2 pixelScale = vec2(zoo/iResolution.y*iResolution.x/iResolution.y,zoo/iResolution.y);
这行代码根据当前的缩放比率以及显示分辨率计算了像素代表的区域的大小。
float density = clamp((pixelArea - 3.1415926*d*d*k)/pixelArea, 0.0, 1.0);
这行代码根据上文讨论计算了估计密度。
然后剩余代码根据估计密度计算出了像素的灰度值,这部分代码可以更加感性的进行调整,只要能获得更好的显示效果。

着色

上面实现的效果是一张灰度图,如果我们根据某种规则为像素赋予颜色,也许可以获得更加具有美感的显示效果。
todo

转载于:https://www.cnblogs.com/bluebean/p/11177088.html


http://chatgpt.dhexx.cn/article/HFCy23Mg.shtml

相关文章

分形之父 Mandelbrot

著名数学家&#xff0c;被誉为分形之父的Mandelbrot先生&#xff0c;美国时间10月15日在马萨诸塞州剑桥辞世&#xff0c;享年85岁。他用“美丽”改变了我们的世界观&#xff0c;他被认为是20世纪后半叶少有的影响深远而且广泛的科学伟人之一&#xff0c;1993年他获得沃尔夫物理…

Ettercap系列 II:基于命令行界面(结合driftnet截获目标机器正在浏览的图片)

相信跟着这个系列走&#xff0c;一直看到这篇文章的读者已经了解了基于图形化Ettercap的操作&#xff0c;并对Arp欺骗和Ettercap相关的术语有所了解。本篇就如何在命令行界面下操作ettercap&#xff0c;以实现与图形化界面相同的效果展开讨论。可能你会不解&#xff1a;既然我已…

无线局域网的嗅探攻击和防御——ettercap+driftnet

&#xfeff;&#xfeff; 无线局域网的嗅探攻击和防御 -----ettercapdriftnet 1 实验要求和目的 ●了解局域网转发数据的规则与协议 ●了解抓包软件的原理与操作流程 ●对网络中数据传输的协议有更深层次的认识 2 实验原理和背景知识 2.1 抓包软件与分析软件 本次嗅探试验所…

python实现图片嗅探工具——自编driftnet

python实现图片嗅探工具——自编driftnet 前言一、数据包嗅探二、图片捕获三、图片显示及主函数写在最后 前言 想必尝试过中间人攻击&#xff08;MITM)的小伙伴&#xff0c;大概率是知道driftnet的。这是一款简单使用的图片捕获工具&#xff0c;可以很方便的从网络数据包中抓取…

kali中 arpspoof、driftnet、流量转发的图片抓取

1、开启内核转发模式&#xff08;echo 1为转发 echo 0为拦截&#xff09; echo 1 /proc/sys/net/ipv4/ip_forward 配置完成使用命令查看cat /proc/sys/net/ipv4/ip_forward 2、使用 Arpspoof 开始攻击 命令:Arpspoof -i (自己网卡) -t 目标IP 网关 3、打开另一个终端 查看dri…

ARP欺骗攻击(流量图片)——dsniff与driftnet使用

ARP欺骗攻击&#xff08;流量&图片&#xff09; 原理&#xff1a; 首先我们![请添加图片描述](https://img-blog.csdnimg.cn/7de7923387224bcda1ea4be958032ae9.png 要明白何为ARP&#xff08;地址解析协议&#xff09;&#xff1a;是根据 IP地址 获取 物理地址 的一个 TC…

NO.26——利用ettercap和driftnet截获数据流里的图片

原理 Ettercap最初设计为交换网上的sniffer&#xff0c;但是随着发展&#xff0c;它获得了越来越多的功能&#xff0c;成为一款有效的、灵活的中介攻击工具。它支持主动及被动的协议解析并包含了许多网络和主机特性&#xff08;如OS指纹等&#xff09;分析。 Ettercap…

linux嗅探器抓包,Kali Linux 嗅探/欺骗工具 driftnet 教程

日期:2018年01月11日 观看: 13,491 C 次 Driftnet是一个监听网络流量并从它观察到的TCP流中提取图像的程序。有趣的是看到很多网络流量的主机上运行。在实验性增强中,driftnet现在从网络流量中挑选出MPEG音频流,并尝试播放它们。 Driftnet是一款从网络流量捕获图像并将其显…

ARP中使用driftnet工具捕获图片

在进行任何网络攻防实验时&#xff0c;请务必遵守当地法律法规以及道德准则&#xff0c;必须遵守法律规定&#xff0c;只能在合法授权的情况下进行实验和演练。 预备知识 基本网络概念&#xff1a;了解TCP/IP协议、IP地址、MAC地址等基本网络概念。 ARP协议&#xff1a;了解A…

使用Arp欺骗与driftnet工具监听局域网信息

【重点声明】此系列仅用于工作和学习&#xff0c;禁止用于非法攻击&#xff0c;非法传播。一切遵守《网络安全法》 环境&#xff1a; Ubuntu 16.0.4攻击主机&#xff1a;192.168.1.130&#xff0c;Windows10 目标机&#xff1a;192.168.1.219 扫描该网段存活的主机&#xff1…

(arpspoof + driftnet)实现arp欺骗

(arpspoof driftnet)实现arp欺骗 虚拟机环境&#xff1a;kali linux window 7 文章目录 (arpspoof driftnet)实现arp欺骗前言一、安装arpspoof和driftnet二、Attack1.信息收集2.MAC欺骗与流量截图 总结 前言 ARP欺骗&#xff1a;欺骗局域网内主机的网关MAC地址&#xff0c…

自举电路介绍

自举电路也叫升压电路&#xff0c;利用自举升压二极管,自举升压电容等电子元件&#xff0c;使电容放电电压和电源电压叠加&#xff0c;从而使电压升高&#xff0e;有的电路升高的电压能达到数倍电源电压。 升压电路原理 举个简单的例子&#xff1a;有一个12V的电路&#xff0c…

秒懂电容自举电路

自举电容的核心原理是&#xff1a;电容两端电压不能突变。 从这句话中&#xff0c;我们可以获取到两个关键字&#xff1a;两端电压、不能突变。 两端电压指的是电容一边相对另一边的电压&#xff0c;我们知道电压本身就是个参考值&#xff08;一般认定参考GND&#xff0c;认定…

STM32自举程序

空间分布 将flash空间分为自举程序区和应用程序区。 应用程序区存放用户应用程序。 自举程序负责获取用户应用程序数据&#xff0c;并写入应用程序区&#xff0c;实现程序升级。 程序跳转 自举程序需要可以跳转到应用程序区&#xff0c;当然应用程序也可以根据需要设计成可…

自举电路(升压电路)

the boost converter,或者叫step-up converter&#xff0c;是一种开关直流升压电路&#xff0c;它可以是输出电压比输入电压高。基本电路图见图1.假定那个开关(三极管或者mos管)已经断开了很长时间&#xff0c;所有的元件都处于理想状态&#xff0c;电容电压等于输入电压。下面…

Web精美个人网页静态展示

今天和大家分享一个纯用web&#xff08;htmlcssjs&#xff09;实现的一个优美的个人信息菜单资料展示。 项目结构很简单只有一个html文件一个css样式文件以及一个js脚本文件。 项目实现的功能&#xff1a; 1&#xff1a;进入首页是一个天气样式页面&#xff08;显示当前时间…

【测控电路】自举式高输入阻抗放大电路

ref 测控电路第五版 有些传感器输出阻抗很高, 要求其测量放大电路有高输入阻抗. 开环集成运放的输入阻抗通常很高, 反相运放输入阻抗远低于同相运放, 为提高输入阻抗, 可在输入端加接电压跟随器, 但会引入共模误差. 在要求较高的场合下, 可采用高输入阻抗集成运放/采用通用运放…

自举电路工作原理分析

OTL功率放大器中要设自举电路,图18-9所示是自举电路。电路中的C1, R1和R2构成自举电路。C1为自举电容&#xff0c;R1O 隔离电阻&#xff0c;R2将自举电压加到 VT2基极。 向左转 | 向右转 VT1集电极信号为正半周期间VT2导通、放大&#xff0c;当输入VT2基极的信号比较大 时&…

STM32自举程序,你了解多少?

置顶/星标公众号&#xff0c;不错过每一条消息 本文主要讲述STM32启动模式中System memory的内容&#xff0c;以及围绕的相关内容。 1写在前面 STM32中内嵌了一段自举程序&#xff0c;可能很多人不知道。 那段自举程序存放在System memory&#xff08;系统存储器&#xff09;中…

静态网站以及动态网站

学习时间&#xff1a;7月7日-8日 学习素材&#xff1a;B站博主 学习的内容&#xff1a;静态网站以及动态网站 静态网站就是没有采用任何程序开发的网站&#xff0c;纯粹采用HTML语言编写&#xff0c;不要求懂太多网站制作知识&#xff0c;使用一般的软件就可以制作网页了。网页…