3D 曼德博球(Mandelbulb)

Rust 光线步进 + WebGL 渲染

🖱️ 拖拽 旋转  |  🖱️ 滚轮 缩放  |  8 次幂曼德博球

📖 原理说明

曼德博球是曼德博集合在三维空间中的推广。它没有由三角形组成的模型,形状完全由一个数学公式定义,每个像素通过「光线步进」直接从公式计算出来。

🧮算法原理

DE = 0.5 · r · ln r / drdr = 8 · r⁷ · dr + 1
三维迭代公式
把点转换成球坐标 (r, θ, φ),做 8 次幂运算 r⁸ · (sin 8θ cos 8φ, sin 8θ sin 8φ, cos 8θ) 后加回原点坐标,相当于 z² + c 的三维版本。
距离估计
在迭代的同时计算导数 dr = 8 · r⁷ · dr + 1,得到当前点到分形表面距离的下界估计 DE = 0.5 · r · ln r / dr。
球体追踪(Sphere Tracing)
从相机向每个像素发出一条光线。每一步都安全地前进 DE 的距离,因为这么远的范围内一定没有表面。当距离小于 0.001 × 已行进距离 时视为击中表面;超过 40 步或行进超过 10 个单位则视为没有击中,画成背景。
光照
在击中点附近沿 x、y、z 三个方向做中心差分,求 DE 的梯度作为表面法线,再与固定的光照方向做点积,加上环境光,得到明暗。
相机旋转
拖拽改变旋转角度,用 Z·X·Y 旋转矩阵把视线方向变换到世界坐标。

🔄Rust 与 JavaScript 的分工

  1. JSJS 处理拖拽和滚轮,更新旋转角度与缩放。
  2. RustJS 调用 raymarch(400, 400, rx, ry, rz, 缩放, 40)。Rust 在 CPU 上为 16 万个像素逐一做光线步进,返回 RGBA 像素数组。
  3. JSJS 用 texImage2D() 把像素上传为 WebGL 纹理,画一个铺满画布的矩形来显示它。

注意:这里 WebGL 只负责显示,所有三维计算都由 Rust/WASM 在 CPU 上完成。页面加载时会先检测 WebGL 环境,检测结果显示在画布下方。

⚡性能要点

  • 每条光线最多 40 步,每一步都要做一次 8 轮迭代的距离估计,击中后还要额外算 6 次来求法线,计算量很大。底部显示的就是单帧耗时。
  • 只在视角变化时重新计算(needsRender 标记加 requestAnimationFrame 合并),静止时不占用 CPU。

源码crates/graphics/mandelbulb/src/lib.rswww/mandelbulb/index.js