首页
/ three.js DecoratedTorusKnot5a 全解析:装饰纽结曲线家族、参数公式与 TubeGeometry 实操

three.js DecoratedTorusKnot5a 全解析:装饰纽结曲线家族、参数公式与 TubeGeometry 实操

2026-09-06 18:07:43作者:薛曦旖Francesca

DecoratedTorusKnot5a 是 three.js 附加模块(addon)examples/jsm/curves/CurveExtras.js 中提供的一类参数化三维装饰纽结(Decorated Torus Knot)曲线,它继承自核心类 Curve,可以直接作为 TubeGeometry 的路径用于生成管状网格。本文结合官方文档页 docs/pages/DecoratedTorusKnot5a.html.md 与该曲线在仓库中的源码实现,系统讲解其继承关系、scale 参数语义、getPoint 的底层几何公式,并给出可直接运行的建模示例,帮助读者把这一类曲线真正用起来。

three.js 参数化样条曲线管状几何示例渲染截图

一、DecoratedTorusKnot5a 是什么

DecoratedTorusKnot5a(装饰纽结 5a)是 three.js 官方示例中一组"参数化曲线"(parametric curves)集合的成员。CurveExtras.js 文件头部注释将其定性为 "A bunch of parametric curves",其中的曲线公式来自多种数学资料,经过编码成为可复用的 Curve 子类。

这些曲线平时不参与 three.js 核心构建,而是作为附加模块随官方示例一同发布。除 DecoratedTorusKnot5a 之外,同一个文件中还提供 GrannyKnotHeartCurveVivianiCurveTrefoilKnotCinquefoilKnot 以及同属装饰纽结家族的 DecoratedTorusKnot4aDecoratedTorusKnot4bDecoratedTorusKnot5c 等曲线,导出列表可见源码 examples/jsm/curves/CurveExtras.js

从命名可以推断,5a 属于五叶装饰纽结家族的一个变体(同族还有 5c,以及四叶家族的 4a4b)。官方文档页 docs/pages/DecoratedTorusKnot5c.html.md 记录了同名兄弟类。

二、导入方式:addon 必须显式导入

文档页明确指出 DecoratedTorusKnot5a 是附加模块,必须显式导入,这与 three.js 官方对 addons 的安装约定一致。官方文档中的导入写法为:

import { DecoratedTorusKnot5a } from 'three/addons/curves/CurveExtras.js';

对应到当前仓库,源码文件即 examples/jsm/curves/CurveExtras.js。由于该模块内同时导出了多条曲线,也可以像官方示例那样整体导入命名空间后按需取用:

import * as Curves from 'three/addons/curves/CurveExtras.js';

const knot = new Curves.DecoratedTorusKnot5a();

这样做的优点是可以把多条曲线放进一个字典、实现"下拉切换曲线"的交互,官方示例 examples/webgl_geometry_extrude_splines.html 正是采用这一模式。

三、继承关系与 Curve 基类

文档页头部以 Inheritance: Curve → 标注了类的继承链——DecoratedTorusKnot5a 直接继承 Curve,不存在中间父类。这一点在源码中得到了直接印证,examples/jsm/curves/CurveExtras.js 处即为 class DecoratedTorusKnot5a extends Curve

基类 Curve 定义于 src/extras/core/Curve.js,它把 getPoint() 声明为抽象方法(未实现时打印 Curve: .getPoint() not implemented. 警告),并在其之上提供了大量派生的采样工具:

基类方法 说明 与 getPoint 的关系
getPoint( t ) 依据插值因子返回曲线上的点,由子类实现 抽象方法,本类重写
getPointAt( u ) 返回曲线上沿曲线长度均匀分布的点 内部经 getUtoTmapping 换算后调用 getPoint
getPoints( divisions ) 沿参数空间等距取点,共 divisions + 1 个点 循环调用 getPoint
getSpacedPoints( divisions ) 沿弧长等距取点,共 divisions + 1 个点 循环调用 getPointAt

这意味着 DecoratedTorusKnot5a 只要正确实现 getPoint,就能自动获得长度参数化、等距采样、TubeGeometry / ExtrudeGeometry 路径等一整套能力,这也是"曲线类"在 three.js 中被大量复用的设计基础。

四、构造器与 scale 参数

new DecoratedTorusKnot5a( scale : number )

构造器接收唯一可选参数 scale,表示曲线的整体缩放系数。源码实现位于 examples/jsm/curves/CurveExtras.js

constructor( scale = 40 ) {

    super();

    this.scale = scale;

}

两点需要注意的事实:

  1. 构造器默认值:文档页在构造器条目下将参数默认值标注为 1,而 .scale 属性条目下标注默认值为 40;对照源码可以看到实际构造器签名为 scale = 40,与属性默认值一致。也就是说,源码中的真实默认值是 40。为避免歧义,建议在使用时显式传入 scale
  2. 不传参会怎样:由于默认值为 40,new DecoratedTorusKnot5a() 会生成一个坐标跨度约在 ±72(见第五节公式推导)范围内的大尺寸曲线,直接放进默认相机场景中可能会超出视野,需要配合相机距离或网格缩放调整。

五、.scale 属性

属性 scale : number 存放曲线的整体缩放系数,默认值 40。它的语义在 getPoint 返回时体现——所有分量统一乘以 this.scale。缩放不改变曲线的形状与拓扑,只改变空间尺寸,因此在把它当作 TubeGeometry 路径使用时,需要让管道半径与曲线尺寸保持协调(半径过小会出现管道"塌陷"、过大会覆盖纽结自身)。

六、.getPoint() 源码与几何公式解读

方法签名

getPoint( t : number, optionalTarget : Vector3 ) : Vector3
  • t:插值因子,表示曲线上的位置,取值必须在 [0, 1] 区间内;
  • optionalTarget:可选的目标向量,结果直接写入该向量(避免额外分配内存);
  • 返回值:曲线上对应位置的 Vector3
  • 覆盖关系:重写基类 Curve#getPoint(见 src/extras/core/Curve.js)。

完整实现

源码位于 examples/jsm/curves/CurveExtras.js

getPoint( t, optionalTarget = new Vector3() ) {

    const point = optionalTarget;

    const fi = t * Math.PI * 2;

    const x = Math.cos( 3 * fi ) * ( 1 + 0.3 * Math.cos( 5 * fi ) + 0.5 * Math.cos( 10 * fi ) );
    const y = Math.sin( 3 * fi ) * ( 1 + 0.3 * Math.cos( 5 * fi ) + 0.5 * Math.cos( 10 * fi ) );
    const z = 0.2 * Math.sin( 20 * fi );

    return point.set( x, y, z ).multiplyScalar( this.scale );

}

公式拆解

fi = t · 2π,则曲线三轴分量为:

分量 数学表达式
x cos(3·fi) · (1 + 0.3·cos(5·fi) + 0.5·cos(10·fi))
y sin(3·fi) · (1 + 0.3·cos(5·fi) + 0.5·cos(10·fi))
z 0.2 · sin(20·fi)

最后执行 (x, y, z) · scale 整体缩放。这条公式可以从几何上这样理解:

  1. 主绕行(cos(3·fi), sin(3·fi)) 表明在参数 t 从 0 到 1(即 fi 从 0 到 2π)的过程中,曲线在 XY 平面绕行 3 圈,构成纽结的主体环圈;
  2. 装饰调制:括号内的 1 + 0.3·cos(5·fi) + 0.5·cos(10·fi) 是沿环圈的径向"装饰"——振幅 0.3、频率 5 的低频起伏叠加振幅 0.5、频率 10 的高频起伏,使环圈半径随绕行不断波动,形成凹凸的"装饰"截面轮廓,这也是它区别于普通 TorusKnot 曲线的关键;
  3. Z 轴起伏0.2·sin(20·fi) 以 20 倍频率让曲线在垂直方向上下摆动,把平面绕行"抬升"成三维空间中的编织感;
  4. 周期性t = 0t = 1 时公式取值完全相同(fi 相差 2π,三角函数周期一致),因此曲线天然闭合,适合构造 closed = trueTubeGeometry
  5. 尺寸量级:未缩放时(scale = 1)三个分量的理论极值约落在 [-1.8, 1.8](XY)与 [-0.2, 0.2](Z),乘以默认 scale 40 后 XY 跨度可达 ±72 左右。

七、配套示例:webgl_geometry_extrude_splines

官方示例 examples/webgl_geometry_extrude_splines.html 是展示这些参数曲线的标准参考:它以命名空间方式导入 CurveExtras.js,把包括 DecoratedTorusKnot5a 在内的一众曲线实例化并放入 splines 字典:

DecoratedTorusKnot5a: new Curves.DecoratedTorusKnot5a(),

随后通过下拉列表在字典中选取当前路径,用 TubeGeometry 生成管状几何并叠加线框网格展示:

tubeGeometry = new THREE.TubeGeometry( extrudePath, params.extrusionSegments, 2, params.radiusSegments, params.closed );

其中 extrusionSegments(示例中为 100)控制沿路径的分段数,分段越密曲线越平滑;radiusSegments 控制管道截面的细分;closed 置为 true 时首尾相接,恰好契合第五节证明的曲线闭合特性。由于 DecoratedTorusKnot5a 默认 scale = 40,示例还单独通过 mesh.scale 对网格做整体缩放以适配相机。阅读该文件 examples/webgl_geometry_extrude_splines.html 可以了解完整的曲线注册与切换逻辑。

八、实操:一段可直接运行的完整示例

下面给出将 DecoratedTorusKnot5a 转成可见三维网格的最小完整流程,思路与官方示例一致:参数曲线做路径 → TubeGeometry 沿线扫掠 → 加入场景。为便于展示,这里显式把 scale 设为 10 并配以相应半径:

import * as THREE from 'three';
import { DecoratedTorusKnot5a } from 'three/addons/curves/CurveExtras.js';

// 1. 构造装饰纽结曲线(显式指定缩放,避免依赖默认值)
const curve = new DecoratedTorusKnot5a( 10 );

// 2. 用曲线作为路径生成管状几何
//    TubeGeometry( path, tubularSegments, radius, radialSegments, closed )
const geometry = new THREE.TubeGeometry( curve, 400, 1.2, 12, true );

// 3. 组装网格并加入场景
const material = new THREE.MeshStandardMaterial( { color: 0x8844ff, metalness: 0.3, roughness: 0.4 } );
const mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );

// 4. 相机距离要覆盖曲线跨度(scale=10 时 XY 跨度约 ±18,加上管道半径)
camera.position.set( 0, 0, 45 );

同样的曲线也可以不经网格化而直接参与动画:利用 curve.getPoints( n ) 生成折线 Line,或用 getPointAt 让物体沿弧长匀速巡游(因为曲线闭合,非常适合做循环运动路径)。

九、常见问题与使用建议

  • 为什么形状与我预期的环面纽结不同? DecoratedTorusKnot5a 的公式是"基环 + 多频调制 + Z 轴高频起伏"的组合,与 TorusKnotGeometry 这类网格几何体是不同的生成途径。它以公式定义一条空间曲线,外观取决于管道半径、分段数与调制频率的相互作用。
  • 修改外观调什么? 管道半径与 tubularSegmentsTubeGeometry 控制;若要改变"装饰"形态,则需要修改 CurveExtras.js 中公式的系数与频率(属于源码定制范畴,仅用于理解原理)。
  • 性能注意TubeGeometry 的顶点数为 (tubularSegments + 1) × (radialSegments + 1)DecoratedTorusKnot5a 的高频调制需要足够的 tubularSegments(通常 200 以上)才能表现平滑,示例中使用的 100 是兼顾预览与性能的经验值。
  • 同一文件的其他曲线:若需要不同形态的装饰纽结,可直接对比同文件内的 DecoratedTorusKnot4aDecoratedTorusKnot4bDecoratedTorusKnot5c,它们各自的 getPoint 中频率与系数组合不同,选择与展示方式完全一致。

十、参考路径速查

掌握 DecoratedTorusKnot5a 的类结构、参数语义与底层公式之后,你既可以照官方示例在 TubeGeometry 中直接使用它生成装饰性网格,也可以把这类周期闭合曲线当作相机轨道、粒子路径或沿路动画的底层工具,充分发挥 three.js Curve 抽象体系的能力。

登录后查看全文
热门项目推荐
相关项目推荐