🌌 探索虚空中的结构:光线步进与 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 创建粘液怪兽?
相关推荐
万少6 小时前
HarmonyOS 开发必会 5 种 Builder 详解
前端·harmonyos
橙序员小站8 小时前
Agent Skill 是什么?一文讲透 Agent Skill 的设计与实现
前端·后端
炫饭第一名10 小时前
速通Canvas指北🦮——基础入门篇
前端·javascript·程序员
王晓枫11 小时前
flutter接入三方库运行报错:Error running pod install
前端·flutter
符方昊11 小时前
React 19 对比 React 16 新特性解析
前端·react.js
ssshooter11 小时前
又被 Safari 差异坑了:textContent 拿到的值居然没换行?
前端
曲折11 小时前
Cesium-气象要素PNG色斑图叠加
前端·cesium
Forever7_11 小时前
Electron 淘汰!新的桌面端框架 更强大、更轻量化
前端·vue.js
Angelial11 小时前
Vue3 嵌套路由 KeepAlive:动态缓存与反向配置方案
前端·vue.js
jiayu12 小时前
Angular学习笔记24:Angular 响应式表单 FormArray 与 FormGroup 相互嵌套
前端