当前位置: 首页 > news >正文

曼德勃罗集的 Three.js 实现

效果预览

经典的曼德勃罗集(Mandelbrot Set)分形渲染,配合动态缩放动画探索分形边界的无限细节。使用线性插值平滑着色,呈现出彩虹般的色彩过渡。

👉 点击查看《曼德勃罗集的》完整源码与效果演示

Shader 实现原理

1. 整体思路与数学模型

曼德勃罗集是复平面上的一组点,对于每一个复数c,迭代序列:

z_{n+1}=z_n^2 + c, z_0=0

如果该序列不发散(即模长始终保持有界),则c属于曼德勃罗集。在计算机中,我们用有限迭代次数来近似判断:如果在res次迭代内|z| > 2,则认为序列发散,c不属于曼德勃罗集。

这个判据的数学依据是:如果|z_n| > 2,序列必然发散到无穷。2是曼德勃罗集的逃逸半径。

2. 复数乘法 — cprod 宏的数学

#define cprod(a, b) vec2(a.x*b.x-a.y*b.y, a.x*b.y+a.y*b.x)

这是标准的复数乘法公式。设a = a.x + i*a.yb = b.x + i*b.y,则:

a * b=(a.x + i*a.y)(b.x + i*b.y)=a.x*b.x - a.y*b.y + i(a.x*b.y + a.y*b.x)

实部a.x*b.x - a.y*b.y对应vec2的 x 分量,虚部a.x*b.y + a.y*b.x对应 y 分量。这个宏把复数运算封装为vec2运算,在 GPU 上是零开销的(编译期展开)。

3. 迭代核心 — mandel 函数

float mandel(vec2 c, int res) { vec2 z = vec2(0.0, 0.0); float oldLen = 0.0; for (int i = 0; i < res; i++) { z += c; z = cprod(z, z); float newLen = length(z); if (newLen > 2.0) { float p = (2.0 - oldLen) / (newLen - oldLen); return float(i) + p; } oldLen = newLen; } return float(res); }
3.1 迭代顺序

注意这里的迭代顺序是先z += cz = z^2。这与标准定义z = z^2 + c等价,但计算顺序不同:

标准定义:z_{n+1} = z_n^2 + c
代码实现:z_{n+1} = (z_n + c)^2 = z_n^2 + 2*z_n*c + c^2

等等,这不相等。实际上仔细看代码:

  • 初始z = 0
  • 第 1 次:z = 0 + c = c,然后z = c^2。此时z = c^2,但标准应该是z = 0^2 + c = c

这个顺序实际上是z_{n+1} = (z_n + c)^2,与标准定义不同。但由于初始值z_0 = 0,两种顺序的差异只是索引偏移一位:

  • 代码中第i次迭代后,z的值对应标准定义的第i+1次迭代
  • 最终返回的迭代次数与标准定义一致(因为初始oldLen = 0已经考虑了第 0 步)
3.2 线性插值平滑(Smooth Iteration Count)
float p = (2.0 - oldLen) / (newLen - oldLen); return float(i) + p;

如果不做平滑,返回的是离散的整数迭代次数。在分形边界处,相邻像素的迭代次数可能相差很大,导致明显的色带(banding)。

线性插值的思路:假设|z|oldLennewLen是线性增长的,则逃逸时刻|z| = 2发生在迭代之间的一个分数位置p

oldLen + p *(newLen - oldLen)=2=>p=(2- oldLen)/(newLen - oldLen)

这样返回值是连续的浮点数,而非离散的整数,消除了色带现象。

4. 坐标变换与缩放系统

vec2 uv = vec2(gl_FragCoord.xy - iResolution.xy / 2.0); uv = uv * 2.0 / min(iResolution.x, iResolution.y);
4.1 屏幕坐标到归一化坐标
  • gl_FragCoord.xy - iResolution.xy / 2.0:将坐标原点移到屏幕中心
  • * 2.0 / min(iResolution.x, iResolution.y):以屏幕短边为基准归一化,保证不同宽高比下图形不被拉伸
4.2 动态缩放
float range = sin(iTime * 0.25) * 0.5 + 0.5; float zoom = 1.0 + 100050.0 * range;
  • sin(iTime * 0.25)周期为2π / 0.25 = 8π ≈ 25.1
  • * 0.5 + 0.5映射到[0, 1]
  • zoom范围:1.0100051.0,覆盖从全局视图到极深放大
4.3 焦点位置
vec2 focus = 1.0 * vec2(-0.542738427, 0.615566608);

这个点是曼德勃罗集边界上一个著名的" elephants valley "(象谷)区域附近的点,分形细节极其丰富。缩放时以此为中心,可以观察到无限递归的自相似结构。

4.4 最终 UV 变换
float f = mandel(focus + uv * 1.25 / zoom, res);
  • uv * 1.25 / zoom1.25是基础视野范围,/ zoom是缩放因子
  • focus + ...:将局部坐标平移到焦点位置

5. 颜色映射

float p = f / float(res); vec3 col = vec3(0.1, 0.1, 0.1); if (int(f) < res) { p *= float(res) / 16.0; col = 0.5 + 0.5 * vec3(sin(p), sin(p + PI / 3.0), sin(p + PI * 2.0 / 3.0)); col = col / max(col.x, max(col.y, col.z)); }
5.1 集合内外的区分
  • int(f) < res:如果迭代次数小于最大迭代次数,说明点在集合外(逃逸了)
  • int(f) == res:点在集合内,使用深色vec3(0.1)
5.2 色相循环
col = 0.5 + 0.5 * vec3(sin(p), sin(p + PI / 3.0), sin(p + PI * 2.0 / 3.0));

这是相位偏移的正弦函数,三个通道的相位差分别为0π/32π/3

  • R 通道:sin(p)
  • G 通道:sin(p + π/3)
  • B 通道:sin(p + 2π/3)

0.5 + 0.5 * sin(...)把输出映射到[0, 1]。三个通道相位差 120°,在 RGB 空间中形成平滑的色相循环。

p *= float(res) / 16.0把迭代计数放大512/16 = 32倍,让颜色变化更频繁,增强视觉细节。

5.3 归一化增强对比
col = col / max(col.x, max(col.y, col.z));

这一步把颜色除以最大通道值,使至少一个通道达到 1.0。效果是:

  • 增强颜色饱和度
  • 让暗色更暗、亮色更亮
  • 整体对比度提升

总结

这个特效的精髓在于用最简单的复数迭代公式生成无限复杂的分形图案。曼德勃罗集不是"画"出来的,而是"算"出来的 —— 每个像素的颜色都是一次独立的数学实验结果。

分形的核心魅力是自相似性:无论你放大多少倍,边界的褶皱结构始终保持相似。本 shader 通过sin(iTime)驱动的动态缩放,让用户能一窥这种无限递归的美。

http://www.jsqmd.com/news/866466/

相关文章:

  • NotebookLM P值不显示?3种隐藏调用方式+2个API绕过技巧,限时公开
  • 达梦数据创建备份文件脚本
  • 在多模型间灵活切换时Taotoken模型广场的选型体验
  • 莆田各区房屋反复漏水真实原因解析:多数维修问题出在工艺匹配度 - 鲁顺
  • 添价收领衔2026广州名表回收六强真机实测:五款腕表横评告诉你谁报价最高 - 薛定谔的梨花猫
  • DeepSeek开源生态已悄然覆盖83%国产芯片栈(昇腾/寒武纪/海光),但官方文档仍未披露的3个兼容补丁即将下线
  • SQL 排序分页精讲!ORDER BY+LIMIT 全套用法,报表分页
  • 为openclaw工具配置taotoken作为ai提供商的具体步骤与注意事项
  • 2026年RPA机器人解决方案选型指南:场景化落地适配
  • 威海各区房屋反复漏水真实原因解析:多数维修问题出在工艺匹配度 - 鲁顺
  • 【紧急修复】Perplexity同义词推荐突然失准?3分钟诊断清单+3个冷启动fallback方案(含Hugging Face最新patch)
  • 360浏览器隐私怎么清理?【图文讲解】360浏览器缓存清理?360浏览器上网痕迹清除?浏览器删除Cookie密码?共用电脑隐私清理?
  • AWS Security Agent 实战:全仓代码扫描 + 自动修复建议完整流程
  • 智慧渔业之鱼分类检测数据集 鱼类分类识别数据 鱼种类分类识别数据集 鱼识别数据集
  • # 2026年西藏旅游团家庭亲子推荐:线路适配与高原保障全解析 - 科技焦点
  • 独立开发者如何管理多个项目的API Key与访问权限
  • 外审员vs内审员具体做什么?需要什么能力? - 众智商学院职业教育
  • 为Claude Code配置Taotoken后端解决访问不稳定与Token不足问题
  • 宜昌各区房屋反复漏水真实原因解析:多数维修问题出在工艺匹配度 - 鲁顺
  • E.位运算-异或:2317. 操作后的最大异或和
  • 在stm32边缘计算场景中观测大模型api用量与成本控制
  • 宁德各区房屋反复漏水真实原因解析:多数维修问题出在工艺匹配度 - 鲁顺
  • 郴州各区房屋反复漏水真实原因解析:多数维修问题出在工艺匹配度 - 鲁顺
  • # 热门国产三维扫描仪推荐:2026年5大核心维度横向对比与避坑指南 - 科技焦点
  • # 2026年便携式三维扫描仪推荐:从便携性、性价比全方面解析 - 科技焦点
  • 如何用 Python 快速接入 Taotoken 并调用多个大模型
  • Kemono-scraper:构建企业级数字艺术资产管理系统的5大核心技术方案
  • 全系列工业仪器仪表国产源头厂家有哪些?2026年五大品牌盘点 - 科技焦点
  • 2026年无锡品牌首饰回收实测:添价收黄金奢侈品回收靠谱 - 薛定谔的梨花猫
  • 添价收发布2026广州名表回收全流程指南:六家机构横向对比手把手教新手卖表 - 薛定谔的梨花猫