🌌 探索虚空中的结构:光线步进与 Marching Cubes 的奇幻冒险

"我不是在看见形状,我是在穿越一片没有定义的空间。"

------ 一个刚刚学会 SDF 的光线


🧭 前言:图形学,也讲浪漫主义

在经典图形学的渲染舞台上,光线追踪是老牌演员,像个理工科贵族一样追踪光线与三角形的命运纠缠。但今天,我们要换个思路。

我们要走进一片未知的空间,不用三角形,不用网格,而是:

  • 在密度场中穿行
  • 用距离场感知世界
  • 用 marching cubes 唤醒形状

这是一段属于**Ray Marching(光线步进)Marching Cubes(行进立方体)**的故事。


🛰️ 一、Ray Marching 是什么?一次可控的冒险

Ray Marching(光线步进),是一种用来在隐式表面中检测交点的方式。

不像光线追踪一头撞向三角形,Ray Marching 更像一个小心翼翼的探险家:

"我不会直接撞上去,我会一步一步接近你,直到靠得不能再近。"

它最常用于:

  • 🪐 渲染 Signed Distance Fields(SDF)
  • 🌫️ 体积效果(如烟雾、云)
  • 🎨 Procedural Art(程序化艺术)

🚶‍♂️ 二、步进的旅程:SDF + 逐步靠近

光线步进的关键思维方式是:

  1. 你从相机发出一条光线。
  2. 沿着光线方向前进。
  3. 每次前进的距离是当前位置距离最近物体表面的"安全距离"。
  4. 如果这个距离非常小,说明你快撞上了,停下来。
  5. 否则,继续走。

"每一步都走得恰到好处,既不多也不少。"

💡 用代码描述一次步进旅程

csharp 复制代码
function rayMarch(origin, direction, maxSteps = 100, maxDist = 100, epsilon = 0.001) {
  let totalDist = 0
  for (let i = 0; i < maxSteps; i++) {
    const currentPoint = origin.clone().add(direction.clone().multiplyScalar(totalDist))
    const dist = sceneSDF(currentPoint)
    if (dist < epsilon) {
      return currentPoint // 命中
    }
    if (totalDist > maxDist) break
    totalDist += dist
  }
  return null // 没找到交点
}

🧠 三、SDF:光线的第六感

SDF(Signed Distance Function)就是给你一个点,它告诉你"离最近的表面有多远",而且还告诉你方向(正/负)。

✨ 例如,球的 SDF:

arduino 复制代码
function sphereSDF(point, center, radius) {
  return point.distanceTo(center) - radius
}

就像是:

"我离球面还有 2 米,那我就可以放心大胆往前走 2 米。"

多个形状还能合成:

javascript 复制代码
function sceneSDF(p) {
  const d1 = sphereSDF(p, new THREE.Vector3(0, 0, 0), 1)
  const d2 = sphereSDF(p, new THREE.Vector3(1.5, 0, 0), 1)
  return Math.min(d1, d2)
}

🧱 四、Marching Cubes:点亮体素空间的雕刻师

Ray Marching 在虚空中穿梭,而 Marching Cubes 则像是在虚空中"建模"。

它的工作方式如下:

  1. 把三维空间切成一个个小立方体(Voxel Grid)
  2. 每个角点都有一个标量值(比如密度、距离)
  3. 如果某些角点在表面之内,而另一些在外,就说明这个立方体被表面穿过
  4. 然后按照固定的规则(256 种情况),用三角形逼近这个表面

"我不关心表面是什么公式,我只关心它穿过了哪些格子。"

🗺️ 三维网格 + 阈值 = 隐式建模

ini 复制代码
for (let x = 0; x < gridSize; x++) {
  for (let y = 0; y < gridSize; y++) {
    for (let z = 0; z < gridSize; z++) {
      const cube = sampleCube(x, y, z)
      const triangles = marchingCube(cube, isovalue)
      geometry.push(...triangles)
    }
  }
}

🎨 五、三维创世神:Ray Marching + Marching Cubes 联手建模

  • 用 SDF 描述形状(光线步进)
  • 用网格转换成可见表面(marching cubes)

这是 Shader 艺术家和体素科学家都爱的组合。

你可以:

  • 🌋 渲染三维爆炸的体积密度场
  • 🧠 建模医学 CT 扫描数据
  • 🪄 创建 procedural 生成的地形、怪物、形状

🧪 示例:创建一个动态"波动球"场景

csharp 复制代码
function sceneSDF(p) {
  const base = sphereSDF(p, new THREE.Vector3(0, 0, 0), 1)
  const noise = Math.sin(p.x * 10 + time) * 0.1
  return base + noise
}

让你的世界跳动起来!


🛠️ 六、用 Three.js 玩起来(理论→实践)

虽然 Ray Marching 和 Marching Cubes 都在 Shader 世界中更常见,但你可以用 JavaScript 实现一个简化版本。

ini 复制代码
const resolution = 30
const mesh = generateMarchingCubesMesh(resolution, sceneSDF)
scene.add(mesh)

你甚至可以把 sceneSDF 替换成任何你想象中的公式,或者直接从 Perlin Noise 构建地下城!


📚 七、知识小结:当几何不是显式时

技术 本质 用途 优势
Ray Marching SDF + 步进 呈现隐式形状、体积效果 可视化无限细节
Marching Cubes 网格构造器 从数据生成形状 可生成可渲染模型
SDF 点 → 距离函数 建模、判断、体积光线 表达简单,组合灵活

🎆 八、结语:在不可见中雕刻世界

"当你无法准确描述一个形状,不妨退一步,只描述它的'感觉'。"

Ray Marching 和 Marching Cubes 让我们不再依赖笨重的几何建模,而是像一个魔法师,从密度、距离、渐变中召唤形状、雕刻体积。

在未来图形渲染、游戏、XR 和科学可视化中,它们会是你不可或缺的光影法术。


🧪 想继续试试:

  • 实时生成的 SDF Shader 场景?
  • Three.js + WebGL2 的体积渲染管线?
  • 用 Marching Cubes 创建粘液怪兽?
相关推荐
小码哥_常1 分钟前
Android开发自救指南:当大图遇上OOM,这波操作能保命!
android·前端
jsonchao4 分钟前
阿里毕业 2 个多月后,我闲着无聊做了 1 个小游戏平台
前端
支撑前端荣耀5 分钟前
十四、Cypress持续集成实践——让测试融入开发流水线
前端
今晚一定早睡6 分钟前
new操作符
前端·javascript·typescript
爱编程的喵7 分钟前
JavaScript数组高级玩法:从入门到放弃再到精通
javascript
尘心cx11 分钟前
前端-CSS-day6
前端·css
骑驴看星星a12 分钟前
定时器与间歇函数
javascript·redis·学习·mysql·oracle
红衣信12 分钟前
useContext 与 useReducer 的组合使用
前端·react.js·面试
拉不动的猪18 分钟前
针对初学者的JS八种类型实用小技巧总结
javascript·css·面试
20 分钟前
Android本地浏览PDF(Android PDF.js 简要学习手册)
android·javascript·pdf