使用 Perlin Noise、Catmull-Rom 创建闭合平滑曲线
2025-4-12
| 2025-4-12
Words 3285Read Time 9 min
type
status
date
slug
summary
tags
category
icon
password

效果预览

fig.1 demo 演示效果(小小的遗憾,没能快乐的循环)
fig.1 demo 演示效果(小小的遗憾,没能快乐的循环)
 
前几天在 openprocessing 闲逛时,偶然发现了一个特别吸引我的动画效果——闭合的平滑曲线如同水波般优雅地流动变换。无独有偶,在一款白噪音助眠应用"潮汐"的界面中也看到过极为相似的设计语言,流畅的曲线随着声音节奏轻轻起伏,营造出令人放松的视觉效果。
最让我惊讶的是,这个即简约又充满韵律感的动画效果,核心代码竟然只有短短几行
而其中最关键的,是两个函数
出于好奇,我试着去研究它们的实现原理,这个过程让我再次感受到,数学的魅力无处不在。

Perlin Noise

认识 Noise 函数

Perlin Noise(柏林噪声)是由计算机科学家 Ken Perlin 在 1983 年提出的一种梯度噪声算法。它能够生成自然、连续且随机的数值,广泛应用于计算机图形学、游戏开发和模拟自然现象(如地形、云层、火焰等)。与纯粹的随机噪声不同,Perlin Noise 具有平滑过渡的特性,使其更接近真实世界的自然纹理。
Perlin Noise 通过在空间中划分网格,并在每个网格节点上赋予随机梯度向量,然后通过插值计算出任意点的噪声值。这种算法能够在多次调用(相同的输入参数)时保持一致的数值,适合用于需要连续性和一致性的场景。

Perlin Noise 原理

Perlin Noise 的核心思想是通过插值使随机值平滑过渡。其实现步骤大致如下
  1. 网格定义:将空间划分为规则的网格,每个网格顶点分配一个随机梯度向量(单位向量)。
  1. 点积计算:对于空间中的任意一点,找到其所在网格的四个顶点,并计算该点到顶点的向量与顶点梯度向量的点积。
  1. 插值平滑:使用缓和曲线(如五次多项式)对四个顶点的点积结果进行双线性插值,确保噪声平滑过渡。
通过调整频率(网格密度)和叠加多层噪声(分形噪声),可以生成更复杂的自然效果。Perlin Noise 因其计算高效和自然表现,成为程序生成内容的重要工具。

MatheMatica 演示 Perlin Noise 的计算

fig.2 2D Perlin Noise
fig.2 2D Perlin Noise
fig.3 3D Perlin Noise
fig.3 3D Perlin Noise

Catmull-Rom

认识 Catmull-Rom 样条曲线

Catmull-Rom 样条曲线是一种插值样条曲线,由 Edwin Catmull 和 Raphael Rom 提出。它能够平滑地穿过给定的控制点,适用于动画路径、相机轨迹和曲线拟合等场景。与 Bézier 曲线不同,Catmull-Rom 曲线保证经过每一个控制点,同时保持局部平滑性,使其在交互式设计中非常实用。

Catmull-Rom 样条曲线原理

Catmull-Rom 曲线的计算基于分段三次插值,其核心步骤如下:
  1. 局部控制:每四个相邻控制点(Pi−1,Pi,Pi+1,Pi+2)确定一段曲线,仅影响 Pi 到 Pi+1 之间的路径。
  1. 插值公式:使用 Hermite 插值形式,计算当前点 t∈[0,1] 的位置:
    1. 张力参数(可选):可通过调整参数控制曲线的“紧度”,默认值为 0.5(均匀 Catmull-Rom 曲线)。
    Catmull-Rom 曲线无需额外锚点,计算高效,且天然保持 C1 连续性,适合实时应用。

    MatheMatica 演示 Catmull-Rom 样条曲线的计算

     
    fig.4 Catmull-Rom 计算示例
    fig.4 Catmull-Rom 计算示例
     
    感兴趣的可以对比下 使用四段三次 Bézier 曲线拟合圆 中的贝塞尔曲线的计算示例图,同样四个点下不同的曲线表现

    Android 中的实现

    使用 Android 版的 Processing 开源框架

    克隆源码 processing (android),主要使用其中的 processing-core 模块, 可在 module 下的 build.gradle 文件中引入
    在 Activity 布局中添加 PFragment
    SketchBubble 中即是具体的动画实现
    你可能会遇到的问题
    processing (android) 中 curve 相关的绘制有个 bug ——无法清除之前的绘制,调试发现 path 没有进行重置,具体代码如下
    page icon
    创意编程还是直接使用 Processing JavaScript 更为高效。相比之下,使用 Android 进行开发不仅繁琐,还受到诸多限制,这让整个过程失去了不少乐趣。

    自己动手实现

    Android 可以使用自定义 View,覆盖 View::onDraw(),使用 Canvas 进行绘制
     

    参考文档

    后记:优秀的交互设计,往往来源于对基础技术的创造性运用。
    后记:优秀的交互设计,往往来源于对基础技术的创造性运用。
     
  2. Android
  3. 建站之初使用 Figma 制作流程图、时序图、幻灯片
    Loading...