Skip to content

程序化几何体

本文档介绍 three.js 中的程序化几何体生成器,重点介绍 ExtrudeGeometryTextGeometry 和参数化曲面生成器。这些类在运行时从 2D 形状、数学函数或 3D 曲线创建 3D 几何体,无需外部模型文件。

程序化生成器不同于 几何体系统 中介绍的基元几何体(立方体、球体、圆柱体)。有关加载预制 3D 模型的信息,请参阅 GLTF 导入与导出附加格式加载器。有关序列化程序化几何体的信息,请参阅 场景序列化

概述

程序化几何体生成器从参数描述创建复杂的 3D 形状:

  1. 基于形状的生成器ExtrudeGeometryTextGeometryShapeGeometry - 将 2D 形状转换为 3D 网格
  2. 参数化生成器ParametricGeometryTubeGeometryLatheGeometry - 计算数学函数以创建曲面
  3. 基础基础设施ShapePathCurve 类定义用于拉伸的 2D 轮廓

所有程序化几何体都扩展 BufferGeometry,并以编程方式填充 positionnormaluv 属性。主要工作流程为:定义 2D 形状 → 配置拉伸/生成参数 → 生成 BufferGeometry

形状与路径系统

程序化几何体的基础是 2D 形状系统,它使用曲线和路径定义轮廓和孔洞。

SVG
100%

2D 形状定义的类层次结构

Curve

提供插值方法的基类。关键方法:

  • getPoint(t):返回参数 t ∈ $$0,1$$ 的向量
  • getPoints(divisions):使用 getPoint() 返回点数组
  • getSpacedPoints(divisions):使用弧长返回等距点
  • computeFrenetFrames(segments, closed):计算切线、法线、副法线框架(用于路径拉伸)

Path

扩展 CurvePath 以提供类似 HTML5 Canvas 2D 的绘图 API:

  • moveTo(x, y):设置绘图偏移
  • lineTo(x, y):添加线段
  • quadraticCurveTo(cpX, cpY, x, y):添加二次贝塞尔曲线
  • bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, x, y):添加三次贝塞尔曲线
  • arc(x, y, radius, startAngle, endAngle, clockwise):添加圆弧
  • ellipse(x, y, xRadius, yRadius, startAngle, endAngle, clockwise):添加椭圆弧

Shape

扩展 Path 以增加孔洞支持:

  • holes:表示内部孔洞的 Path 对象数组
  • extractPoints(divisions):返回带镶嵌点的 {shape: Vector2[], holes: Vector2[][]}

ExtrudeGeometry

ExtrudeGeometry 通过沿 Z 轴或自定义 3D 路径拉伸将 2D 形状转换为 3D 几何体。它支持倒角边缘以实现平滑过渡。

构造函数与选项

// 签名
new ExtrudeGeometry(shapes, options)

选项对象(ExtrudeGeometry~Options):

属性类型默认值描述
curveSegmentsnumber12曲线上的点数
stepsnumber1沿拉伸深度的细分数
depthnumber1拉伸形状的深度
bevelEnabledbooleantrue启用倒角
bevelThicknessnumber0.2倒角进入形状的深度
bevelSizenumberbevelThickness - 0.1倒角从轮廓延伸的距离
bevelOffsetnumber0倒角开始的轮廓距离
bevelSegmentsnumber3倒角层数
extrudePathCurvenull用于拉伸的 3D 样条路径(禁用倒角)
UVGeneratorObjectWorldUVGenerator自定义 UV 生成函数

拉伸管线

SVG
100%

ExtrudeGeometry 处理流程

关键算法

倒角向量计算

getBevelVec() 函数 src/geometries/ExtrudeGeometry.js236-357 计算倒角的偏移向量:

  1. 对于每个轮廓顶点,找到前一个和后一个顶点
  2. 计算归一化边向量
  3. 检查边是否共线(叉积 ≈ 0)
  4. 如果不共线:计算偏移平行边的线-线交点
  5. 如果共线:使用垂直偏移(直边或尖刺情况)
  6. 钳制偏移幅度以防止过度尖刺(最大长度 √2)

通过在平均边方向上垂直偏移顶点,在角落处产生平滑倒角。

重叠点移除

mergeOverlappingPoints() src/geometries/ExtrudeGeometry.js170-202 移除小于缩放阈值的相邻顶点:

THRESHOLD_SQ = 1e-10 * max(|x|, |y|)²

这防止浮点精度问题导致的退化三角形。

三角剖分

使用 ShapeUtils.triangulateShape(contour, holes) src/geometries/ExtrudeGeometry.js402-453 生成面索引。启用倒角时,使用收缩的轮廓顶点和扩展的孔洞顶点创建适当的封盖几何体。

路径拉伸

当指定 extrudePathsrc/geometries/ExtrudeGeometry.js106-125

  1. 使用 getSpacedPoints(steps) 沿路径采样点
  2. 使用 computeFrenetFrames(steps, isClosed) 计算 Frenet 框架(切线、法线、副法线)
  3. 对于每个形状顶点,通过框架变换以沿路径定位
  4. 倒角被禁用(与任意路径不兼容)

形状沿 3D 曲线扫掠,使用 Frenet 框架保持方向。

UV 生成

WorldUVGenerator src/geometries/ExtrudeGeometry.js808-864 提供默认 UV 映射:

  • 顶部 UVgenerateTopUV):在世界空间中使用顶点的 X,Y 坐标
  • 侧壁 UVgenerateSideWallUV):使用变化较大的 X 或 Y 和 1-Z 进行垂直映射

可通过 UVGenerator 选项提供自定义 UV 生成器。

顶点与面构建

几何体分层构建 src/geometries/ExtrudeGeometry.js460-560

  1. 背面顶点(z = 0 或在 extrudePath 起点)
  2. 每个步骤的中间顶点(z = depth * step / steps)
  3. 正面顶点(z = depth 或在 extrudePath 终点)
  4. 前后的倒角顶点(如启用)

使用辅助函数添加面:

源码: src/geometries/ExtrudeGeometry.js460-560 src/geometries/ExtrudeGeometry.js574-683 src/geometries/ExtrudeGeometry.js694-747

TextGeometry

TextGeometry 扩展 ExtrudeGeometry 以从字体数据创建 3D 文本 editor/js/libs/tern-threejs/threejs.js1222-1228

new TextGeometry(text, parameters)

参数 包括标准 ExtrudeGeometry 选项加字体特定属性:

  • font:字体数据对象(通常从 JSON 字体文件加载)
  • size:字体大小(默认 100)
  • height:拉伸深度(映射到 depth 选项)
  • curveSegments:曲线镶嵌(默认 12)
  • bevelEnabled:启用倒角(默认 true)
  • bevelThickness:倒角深度(默认 10)
  • bevelSize:倒角偏移(默认 8)

字体系统使用 FontUtils(或字体加载器)将文本字符串转换为 Shape 对象,然后使用标准 ExtrudeGeometry 管线进行拉伸。

LatheGeometry

LatheGeometry 通过将 2D 轮廓绕 Y 轴旋转创建轴对称曲面。这是用于旋转曲面的程序化生成器。

const points = [
    new Vector2(0, 0),
    new Vector2(10, 0),
    new Vector2(10, 20),
    new Vector2(5, 30)
];
const geometry = new LatheGeometry(points, segments, phiStart, phiLength);

参数:

  • points:定义 2D 轮廓的 Vector2 数组(绕 Y 轴旋转)
  • segments:圆周细分数(默认:12)
  • phiStart:起始角度(弧度)(默认:0)
  • phiLength:扫描角度(弧度)(默认:2π 完整旋转)

常见用例:花瓶、瓶子、碗、建筑柱、灯罩。

参数化几何体

ParametricGeometry

ParametricGeometry 从参数化曲面函数生成几何体 editor/js/libs/tern-threejs/threejs.js1154-1160

function surfaceFunction(u, v, target) {
    // u, v ∈ [0, 1]
    // 设置 target.x, target.y, target.z
}

const geometry = new ParametricGeometry(surfaceFunction, slices, stacks);

函数在 (u,v) 坐标网格上求值:

  • slices:u 方向的细分数
  • stacks:v 方向的细分数

每个网格单元变为两个三角形,创建镶嵌曲面。

TubeGeometry

TubeGeometry 沿 3D 曲线拉伸圆形横截面 editor/js/libs/tern-threejs/threejs.js1246-1269

const path = new CatmullRomCurve3(points);
const geometry = new TubeGeometry(path, tubularSegments, radius, radialSegments, closed);

属性:

  • tangents:沿路径的切向量数组
  • normals:法向量数组
  • binormals:副法向量数组

Frenet 框架向量定义沿路径每个点处圆形横截面的方向。

ShapeGeometry

ShapeGeometry 从形状创建无拉伸的平面(2D)几何体 editor/js/libs/tern-threejs/threejs.js1190-1200

const shape = new Shape();
shape.moveTo(0, 0);
shape.lineTo(0, 10);
shape.lineTo(10, 10);
shape.lineTo(10, 0);
shape.lineTo(0, 0);

const geometry = new ShapeGeometry([shape], options);

这实际上等同于 depth: 0bevelEnabled: falseExtrudeGeometry,但针对 2D 用例进行了优化。它对形状进行三角剖分,仅添加一组顶点(无拉伸层)。

内部工具与模式

程序化几何体生成器使用 ShapeUtils 中的通用内部工具,并遵循标准属性构建模式。

ShapeUtils

ExtrudeGeometry 内部用于 2D 形状处理:

顶点构建模式

所有程序化生成器遵循此 BufferGeometry 构建模式 src/geometries/ExtrudeGeometry.js74-77

  1. 构建平面顶点位置数组(Float32ArrayArray
  2. 构建面索引数组(用于索引几何体)
  3. 创建 BufferAttribute 对象
  4. 调用 this.setAttribute('position', new Float32BufferAttribute(verticesArray, 3))
  5. 调用 this.setAttribute('uv', new Float32BufferAttribute(uvArray, 2))
  6. 调用 this.computeVertexNormals() 自动生成法线

来自 ExtrudeGeometry 的示例:

this.setAttribute('position', new Float32BufferAttribute(verticesArray, 3));
this.setAttribute('uv', new Float32BufferAttribute(uvArray, 2));
this.computeVertexNormals();

内部辅助函数如 scalePt2() src/geometries/ExtrudeGeometry.js222-228 mergeOverlappingPoints() src/geometries/ExtrudeGeometry.js170-202getBevelVec() src/geometries/ExtrudeGeometry.js236-357 展示了整个程序化生成中使用的几何体操作模式。

序列化

程序化几何体通过 toJSON()fromJSON() 模式支持 JSON 序列化。

ExtrudeGeometry 序列化

toJSON() 方法 src/geometries/ExtrudeGeometry.js763-772 序列化:

  • 形状 UUID(形状必须单独序列化)
  • 选项对象
  • ExtrudePath(如存在)通过其自己的 toJSON() 序列化

fromJSON() 静态方法 src/geometries/ExtrudeGeometry.js782-804 重建:

  • 在提供的形状数组中按 UUID 查找形状
  • 使用曲线类型和 Curves[extrudePath.type] 重建 extrudePath
  • 用恢复的参数创建新的 ExtrudeGeometry

此模式在所有程序化几何体中保持一致,允许场景序列化与反序列化并完全重建几何体。详见 场景序列化

与渲染系统集成

所有程序化几何体生成 BufferGeometry 实例,与渲染管线集成:

  1. 顶点属性positionnormaluv(以及可选的 colortangent
  2. 绘制组addGroup(start, count, materialIndex) 支持多材质 src/geometries/ExtrudeGeometry.js626-650
  3. 包围体:通过 computeBoundingBox()computeBoundingSphere() 计算

渲染系统(见 WebGL 渲染器(传统)现代渲染器架构)消费这些属性以上传数据到 GPU 并执行绘制调用。