Marching Squares 算法从原理到实战:以 The Coding Train「Coding in the Cabana 5」存档代码为例

发布时间:2026/10/13 2:13:23
Marching Squares 算法从原理到实战:以 The Coding Train「Coding in the Cabana 5」存档代码为例 教程文档示例工程【免费下载链接】website-archiveArchive of the Coding Train website (first version)项目地址https://gitcode.com/gh_mirrors/we/website-archive点击查看免费下载本文围绕 website-archive 仓库The Coding Train 网站第一版存档中收录的《Coding in the Cabana》第 5 集2020-07-14 发布视频 ID0ZONMNUKTfU展开完整解析 Marching Squares步进方格算法的原理、p5.js 与 Processing 双版本实现以及 Color、Worley Noise、Image、Webcam、Metaballs、Cave Generation、插值增强等 15 个官方变体。读完本文你将掌握如何从 Open Simplex Noise 等标量场生成网格数据、如何用 4 位状态编码查表绘制等值线段、如何通过线性插值消除锯齿状轮廓并知道每一份参考实现的仓库路径。源文档005-marching-squares.md全部示例源码位于 challenges/coding-in-the-cabana/005_marching_squares。一、Marching Squares 是什么从 3D Marching Cubes 到 2D 等值线Marching Squares 是著名的 Marching Cubes 算法见 William E. Lorensen 与 Harvey E. Cline 的经典论文Marching cubes: A high resolution 3D surface construction algorithm在二维平面上的对应物。它解决的问题是给定一张「标量场」scalar field即每个网格点上都存有一个数值高度、密度、亮度、距离等如何用尽量少的线段勾勒出「场值等于某个阈值」的等值线轮廓。在本集的示例中标量场来源于Open Simplex NoiseKurt Spencer 提出的开源噪声算法屏幕上每个采样点得到一个位于[-1, 1]区间的噪声值再引入第三个维度zoff随时间递增让整幅等值线图产生缓慢流动的动画效果。该技术可直接复用到地形等高线、天气图等压线、流体场可视化、程序化洞穴地图、metaballs 有机体造型等场景。算法只做两件事剩下的交给查表采样把画布按rez分辨率步长划分成网格计算每个格点上的场值画线对每个「由 4 个格点围成的小方格」根据 4 个角点与阈值的大小关系查表在方格边缘的中点之间画 02 条线段。二、核心实现逐行解读p5.js 与 Processing 基础版基础版本分别存放在 P5/sketch.js 与 Processing/sketch_marching_squares/sketch_marching_squares.pde两者逻辑完全一致Processing 版使用fullScreen(P2D)全屏渲染并开启pixelDensity(2)。2.1 网格与采样参数let rez 5; // 每个采样格子的像素边长决定轮廓分辨率与性能 let increment 0.1; // 噪声采样时 xoff/yoff 的步进越小轮廓越平滑 let zoff 0; // 噪声第三维每帧递增实现动画 let noise; // OpenSimplexNoise 实例 function setup() { createCanvas(300, 300); noise new OpenSimplexNoise(Date.now()); // 以时间戳做随机种子 cols 1 width / rez; // 列数 1 画布宽 / rez rows 1 height / rez; // 行数 1 画布高 / rez }核心参数速查基础版默认值参数默认值作用与取值范围rez5网格步长像素。越小轮廓越精细、越接近真实等值线但计算量按(width/rez)×(height/rez)平方级上升rez越大线条越「像素风」increment0.1噪声二维采样步进。0.1 时相邻格点场值平滑连续调大如 0.2会让轮廓更碎、斑块更多zoff增量0.03基础版/ 0.02部分变体每帧加到噪声第三维控制动画流速越大流动越快画布300×300P5主版本 Processing 使用fullScreen(P2D)全屏2.2 生成标量场每帧采样 Open Simplex Noisefunction draw() { background(0); let xoff 0; for (let i 0; i cols; i) { xoff increment; let yoff 0; for (let j 0; j rows; j) { field[i][j] float(noise.noise3D(xoff, yoff, zoff)); // 值域约 [-1, 1] yoff increment; } } zoff 0.03; }field[i][j]存的是第i列、第j行格点处的场值。代码中被注释掉的fill(field[i][j]*255); rect(...)片段是调试用的「场值可视化」取消注释即可看到噪声灰度图——这是一种理解标量场的好方法。2.3 状态编码4 位二进制查表对每个小方格取左上a、右上b、右下c、左下d四个角点每个角点与阈值比较后得到 0/1再按权重编码成一个 015 的整数function getState(a, b, c, d) { return a * 8 b * 4 c * 2 d * 1; // 按位权组合成 4 位二进制数 }在基础版中角点值来自ceil(field[i][j])由于 OpenSimplex 输出在[-1,1]ceil之后-1与0都变成 01保持 1——即以 0 为隐式阈值完成二值化在 Metaballs、Image、Webcam 等变体中则显式使用field threshold ? 0 : 1判定。2.4 四个边缘中点与 16 种状态查表每个方格在四条边的中点定义四个候选端点let a createVector(x rez * 0.5, y); // 上边中点 let b createVector(x rez, y rez * 0.5); // 右边中点 let c createVector(x rez * 0.5, y rez); // 下边中点 let d createVector(x, y rez * 0.5); // 左边中点随后按state值从 015 查表连线。完整状态表与 P5/sketch.js 中switch完全对应state含义激活角点绘制的线段说明0无角点激活无四个角点都在阈值同侧等值线不经过1仅左下 dc–d2仅右下 cb–c3右下左下 c,db–d4仅右上 ba–b5右上左下 b,da–d b–c双线对角线交叉情形经典 2×2 边角配置6右上右下 b,ca–c7右上右下左下 b,c,da–d8仅左上 aa–d9左上左下 a,da–c10左上右下 a,ca–b c–d双线对角线交叉情形11左上右上 a,ba–b12左上右上右下 a,b,cb–d13左上右上左下 a,b,db–c14左上右上右下左下缺一c–d15四角全激活无四角都在阈值同侧等值线不经过值得注意的是状态 7 与 8、6 与 9、5 与 10 分别画出了相同的线段它们对应角点激活模式的「互补」情形例如 7 激活了除左上外的三个角8 只激活左上。基础版并未区分这些歧义情况而是统一取固定中点连线视觉上形成「平均化」的平滑轮廓。这正是后续插值变体要改进的地方见第五节。三、16 状态为何只有 14 种画线结果对称性解读从源码的switch分支可以看出case 7与case 8都画a–dcase 6与case 9都画a–ccase 5画a–d b–c而case 10画a–b c–d。这是因为状态 5b、d 激活与状态 10a、c 激活是对角线交叉的两种情况——等值线在两个对角方向都可能出现若不引入插值或额外的连续性判定就只能按固定约定各画两条交叉线段状态 7 与 8、6 与 9 互为旋转/取反对称线段取向相同。在标准 Marching Squares 实现中case 5与case 10的歧义通常通过相邻格子的状态来消解本集的基础版选择了简单固定的连线方案这在小rez细网格下视觉上几乎无感知而插值变体则通过把端点位置按场值比例移动来同时缓解锯齿与歧义。四、运行方式两种语言环境下的完整步骤4.1 p5.js 版本每个P5*目录都是一个独立的 p5.js 工程index.htmlsketch.js打开 challenges/coding-in-the-cabana/005_marching_squares 下任一P5目录方式一将整个目录拖入 p5.js 官方在线编辑器或把sketch.js内容粘贴到编辑器新建 sketch 中方式二本地起一个静态服务器如python3 -m http.server后访问index.html基础版依赖同目录的 OpenSimplexNoise.js若只复制sketch.js需同时带上该文件并在index.html中先行引入。4.2 Processing 版本每个Processing*目录是一个完整的 Processing sketch.pde 依赖的.java/.pde文件打开 Processing IDE基础版建议使用 P2D 渲染器主版本代码中调用fullScreen(P2D)直接打开 Processing/sketch_marching_squares/sketch_marching_squares.pde同目录的 OpenSimplexNoise.java 会被自动编译Webcam 变体需要processing.video库代码首行import processing.video.*并在 setup 中选择可用摄像头Image 变体需要把 image0.jpg 放在 sketch 的data目录中仓库已内置。五、消除锯齿的进阶线性插值变体基础版把线段端点固定在格子边缘中点线条呈「阶梯状」。两个插值变体通过lerp按场值比例移动端点让轮廓更贴近真实等值线。5.1 OpenSimplex 插值变体P5_simplex_interpolation/sketch.js 与 Processing_simplex_interpolation// 把值域 [-1,1] 平移到 [0,2]阈值取 1 let a_val field[i][j] 1; let b_val field[i 1][j] 1; let c_val field[i 1][j 1] 1; let d_val field[i][j 1] 1; // 在每条边上求出场值 阈值的精确位置 let amt (1 - a_val) / (b_val - a_val); a.x lerp(x, x rez, amt); // a 不再固定在边中点而是按比例滑动 a.y y;核心是线性插值公式amt (threshold - v1) / (v2 - v1)当两个角点场值分别位于阈值两侧时等值线与该边交点的位置可由场值比例估算。四条边分别求出a上边、b右边、c下边、d左边的精确交点后再按同一张 16 状态表连线得到的轮廓平滑、无台阶感。相比基础版还额外开启了strokeWeight(2)让线条更醒目。5.2 Metaballs 插值变体P5_metaballs_interpolation/sketch.js含 Bubble.js与 Processing 同名目录直接把上述插值端点替换掉 metaballs 变体的固定中点见下文第六节阈值同样取1。插值后 metaballs 轮廓由生硬的折线变成平滑的有机曲线。六、更多数据源变体让同一套查表吃下不同标量场Marching Squares 的魅力在于只要提供一张场值网格画线逻辑完全不用改。本集正是通过替换场从哪来制造了 7 个变体。6.1 Metaballs场来自距离场叠加P5_metaballs/sketch.js16 个BubbleProcessing 版相同for (let b of bubbles) { sum (b.r * b.r) / ((x - b.x) * (x - b.x) (y - b.y) * (y - b.y)); } field[i][j] sum;每个格点的场值是所有「气泡」半径平方与距离平方之比的和越靠近气泡中心场值越大取阈值1场值大于 1 的区域内部、小于 1 的区域外部边界就是等值线。气泡在 Bubble.js 中带随机速度运动并在画布边缘反弹16 个 blob 时而融合时而分离——这与 Coding Challenge #28 Metaballs作者在videos中引用了该集是同一主题的 Marching Squares 实现。6.2 Worley Noise场来自最近特征点距离P5_worley/sketch.js 与 Processing_worley随机散布若干特征点P5 版 20 个、Processing 版 150 个每个特征点带(x, y, z)三维坐标每个格点计算到所有特征点的距离并排序取第二小距离sorted[1]作为场值这正是本仓库另一集「Coding in the Cabana #4 Worley Noise」的细胞状图案来源P5 版阈值35、Processing 版阈值70配合factor 5放大灰度等值线勾勒出细胞壁般的多边形边界第三维z随帧数推进使图案随时间演化。6.3 Image场来自图片亮度P5_image/sketch.js 与 Processing_imagepreload()/setup()中加载 image0.jpg1920×1080每帧loadPixels()后对每个网格点取该像素的brightness(c)作为场值P5 版阈值90、Processing 版阈值245stroke(255)白色描边叠在图片上勾出亮度等值线类似照片转线稿P5 版末尾调用noLoop()只绘制一帧适合静态出图。6.4 Webcam场来自摄像头画面P5_webcam/sketch.js 与 Processing_webcamP5 版用createCapture(VIDEO)后cam.hide()隐藏原始视频、只取帧像素Processing 版用processing.video.Capture通过Capture.list()枚举设备后取cameras[0]并实现captureEvent()回调持续read()场值同样是像素亮度阈值控制在 80245 之间代码中以注释形式保留了map(mouseX, 0, width, 0, 255)的动态阈值设想黑色描边实时勾勒出画面中最亮区域的轮廓——一个实时「边缘检测」演示。6.5 Color按状态值着色P5_color/sketch.js 与 Processing_colorcolorMode(HSB, 255, 255, 255)切换为 HSB 色彩空间先用半透明描边画出每个网格方格的轮廓square(x, y, rez)再按状态值映射色相stroke(map(state, 0, 15, 0, 360), 200, 255, 255)把 16 种拓扑状态染成不同颜色rez调大到 25、increment调大到 0.2突出「色块马赛克」的装饰效果。七、进阶变体程序化洞穴生成三角形网格版Cave Generation 变体P5_cave/sketch.js P5_cave/squares.js是社区贡献者David Snyder的实现思想来自 Sebastian Lague 的Procedural Cave Generation系列生成洞穴地图用openSimplex.noise3D采样场值小于fillpercent此处为 0的格点标记为墙壁1其余为空洞0地图四周边框强制置1代码中还预留了smoothing(times)函数按 3×3 邻居中墙壁数量4填墙、4挖空可作为后期平滑步骤构建网格squares.js中用ControlNode带above/right两个边缘节点、Node、Square、Grid四个类搭建数据结构——ControlNode是角点其派生出的边缘中点节点用于生成三角形顶点查表出三角网格Square.config用相同的8/4/2/1权重编码 16 种状态triSquare()按状态把边缘中点组合成 36 个顶点再经meshfromPoints()三角剖分fan 式切分生成vertices与tris数组渲染draw()中每帧重建地图与网格用triangle()批量绘制点击鼠标可saveCanvas(c, cave, jpg)保存洞穴截图。这个变体展示了从「画线段」到「填充三角形网格」的升级——它距离 3D Marching Cubes仓库 contribution 中也有 Three.js 与 C/OpenGL 的 3D 移植只有一步之遥。八、官方资源清单与社区衍生作品8.1 官方在线编辑器 Sketch ID以下变体的 p5.js 在线编辑器 sketch ID来自源文档元数据可用于在 p5.js 编辑器中直接打开对照变体sketch ID基础版g6-zufS8cColorhERGV3q_uWorley NoiseJzvYF8WwTImageqThqi4OfJWebcam0XAj0DRD2MetaballswwB-AA4i-Cave Generationz4U3Luf7oMetaballs InterpolationhEB4588QCOpenSimplex Interpolation18cjVoAX18.2 源文档引用的延伸资料均为了解算法脉络的优质入口原始论文Lorensen Cline 的 Marching Cubes 论文算法本源Jamie Wong的《Metaballs and Marching Squares》图解文章Sebastian Lague的两部视频Coding Adventure: Marching Cubes与Procedural Cave Generation (E02. Marching Squares)——后者正是 Cave 变体的灵感来源The Coding Train 关联内容Coding Challenge #28 Metaballs、Coding in the Cabana #4 Worley Noise、OpenSimplex Noise 专题与 2D Perlin Noise 教程仓库对应代码见 CodingChallenges/CC_028_MetaBalls 与 challenges/coding-in-the-cabana/004_worley_noiseOpenSimplexNoise 库仓库为 P5/Processing 各内置了一份实现P5/OpenSimplexNoise.js、Processing/sketch_marching_squares/OpenSimplexNoise.java。8.3 社区贡献作品源文档 contributions 摘录源文档记录了十余个社区衍生实现涉及Python/Pygame 移植、Perlin 场中的 Marching Squares、Python 3D Perlin 版本、p5.js 方形轮廓变体、插值等高线、TypeScript 随机数场版本、Three.js 的 3D Marching Cubes、C/OpenGL Marching Cubes、MarchingRays、基于 metaballs 的「MetaSlime」生物、彩虹 Perlin 场版本以及 p5 中的 Marching Cubes 计算几何演示等。这些作品从侧面印证了同一算法在不同语言、不同场源下的通用性。九、仓库文件导览challenges/coding-in-the-cabana/005_marching_squares/ ├── P5/ # 基础版OpenSimplex 场 ├── P5_cave/ # 洞穴生成三角网格David Snyder ├── P5_color/ # 按 16 状态着色 ├── P5_image/ # 图片亮度场 ├── P5_metaballs/ # metaballs 距离场 ├── P5_metaballs_interpolation/# metaballs 线性插值 ├── P5_simplex_interpolation/ # OpenSimplex 线性插值 ├── P5_webcam/ # 摄像头亮度场 ├── P5_worley/ # Worley 第二近邻距离场 ├── Processing/ # 基础版fullScreen P2D ├── Processing_color/ ├── Processing_image/ # 含 data/image0.jpg 输入图 ├── Processing_metaballs/ ├── Processing_metaballs_interpolation/ ├── Processing_simplex_interpolation/ ├── Processing_webcam/ # 依赖 processing.video └── Processing_worley/每个P5*与Processing*目录一一对应逻辑等价、便于双语对照学习。相关集数文档见 _challenges/coding-in-the-cabana/index.mdWorley Noise 前作见 004-worley-noise.md。十、小结与调参建议Marching Squares 的核心可归纳为三步采样标量场 → 逐格 4 位编码 → 查表连线。快速上手实验时建议先用基础版OpenSimplex 场把rez从 5 调到 220观察精细度与性能的权衡想获得平滑曲线直接用 OpenSimplex Interpolation 变体插值公式amt (threshold - v1)/(v2 - v1)是通用的可移植到任何场源想体会一套查表、无数数据源依次替换场为 metaballs、Worley、图片、摄像头观察同一套 16 状态表的输出差异想做游戏关卡生成直接研究 Cave 变体的三角形网格管线。本集全部源码、依赖文件与配套素材均已收录于本仓库可随时对照运行。赞分享教程文档示例工程【免费下载链接】website-archiveArchive of the Coding Train website (first version)项目地址https://gitcode.com/gh_mirrors/we/website-archive点击查看免费下载相关推荐Worley Noise 细胞噪声从原理到实现Coding in the Cabana 4 源码全解析website-archiveWorley Noise 细胞噪声从原理到实现Coding in the Cabana 4 源码全解析website archive 本文基于 websi教程文档示例工程Coding in the Cabana 第 1 期使用 p5.js 与 Processing 实现 Maurer Rose 可视化Coding in the Cabana 第 1 期使用 p5.js 与 Processing 实现 Maurer Rose 可视化 导读 Maurer Ro教程文档示例工程Coding Train 挑战 169Pi in the Sky —— 用 p5.js 接住从天而降的圆周率数字Coding Train 挑战 169Pi in the Sky —— 用 p5.js 接住从天而降的圆周率数字 每年 3 月 14 日是 Pi Day圆周教程文档示例工程上一篇TorchMetrics终极指南如何用专业指标库提升你的PyTorch模型评估效率下一篇Minikube版本升级完全指南平滑迁移和兼容性保证的最佳实践创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询