程序化几何体
本文档介绍 three.js 中的程序化几何体生成器,重点介绍 ExtrudeGeometry、TextGeometry 和参数化曲面生成器。这些类在运行时从 2D 形状、数学函数或 3D 曲线创建 3D 几何体,无需外部模型文件。
程序化生成器不同于 几何体系统 中介绍的基元几何体(立方体、球体、圆柱体)。有关加载预制 3D 模型的信息,请参阅 GLTF 导入与导出 和 附加格式加载器。有关序列化程序化几何体的信息,请参阅 场景序列化。
概述
程序化几何体生成器从参数描述创建复杂的 3D 形状:
- 基于形状的生成器:
ExtrudeGeometry、TextGeometry、ShapeGeometry- 将 2D 形状转换为 3D 网格 - 参数化生成器:
ParametricGeometry、TubeGeometry、LatheGeometry- 计算数学函数以创建曲面 - 基础基础设施:
Shape、Path、Curve类定义用于拉伸的 2D 轮廓
所有程序化几何体都扩展 BufferGeometry,并以编程方式填充 position、normal 和 uv 属性。主要工作流程为:定义 2D 形状 → 配置拉伸/生成参数 → 生成 BufferGeometry。
形状与路径系统
程序化几何体的基础是 2D 形状系统,它使用曲线和路径定义轮廓和孔洞。
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):
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| curveSegments | number | 12 | 曲线上的点数 |
| steps | number | 1 | 沿拉伸深度的细分数 |
| depth | number | 1 | 拉伸形状的深度 |
| bevelEnabled | boolean | true | 启用倒角 |
| bevelThickness | number | 0.2 | 倒角进入形状的深度 |
| bevelSize | number | bevelThickness - 0.1 | 倒角从轮廓延伸的距离 |
| bevelOffset | number | 0 | 倒角开始的轮廓距离 |
| bevelSegments | number | 3 | 倒角层数 |
| extrudePath | Curve | null | 用于拉伸的 3D 样条路径(禁用倒角) |
| UVGenerator | Object | WorldUVGenerator | 自定义 UV 生成函数 |
拉伸管线
ExtrudeGeometry 处理流程
关键算法
倒角向量计算
getBevelVec() 函数 src/geometries/ExtrudeGeometry.js236-357 计算倒角的偏移向量:
- 对于每个轮廓顶点,找到前一个和后一个顶点
- 计算归一化边向量
- 检查边是否共线(叉积 ≈ 0)
- 如果不共线:计算偏移平行边的线-线交点
- 如果共线:使用垂直偏移(直边或尖刺情况)
- 钳制偏移幅度以防止过度尖刺(最大长度 √2)
通过在平均边方向上垂直偏移顶点,在角落处产生平滑倒角。
重叠点移除
mergeOverlappingPoints() src/geometries/ExtrudeGeometry.js170-202 移除小于缩放阈值的相邻顶点:
THRESHOLD_SQ = 1e-10 * max(|x|, |y|)²这防止浮点精度问题导致的退化三角形。
三角剖分
使用 ShapeUtils.triangulateShape(contour, holes) src/geometries/ExtrudeGeometry.js402-453 生成面索引。启用倒角时,使用收缩的轮廓顶点和扩展的孔洞顶点创建适当的封盖几何体。
路径拉伸
当指定 extrudePath 时 src/geometries/ExtrudeGeometry.js106-125:
- 使用
getSpacedPoints(steps)沿路径采样点 - 使用
computeFrenetFrames(steps, isClosed)计算 Frenet 框架(切线、法线、副法线) - 对于每个形状顶点,通过框架变换以沿路径定位
- 倒角被禁用(与任意路径不兼容)
形状沿 3D 曲线扫掠,使用 Frenet 框架保持方向。
UV 生成
WorldUVGenerator src/geometries/ExtrudeGeometry.js808-864 提供默认 UV 映射:
- 顶部 UV(
generateTopUV):在世界空间中使用顶点的 X,Y 坐标 - 侧壁 UV(
generateSideWallUV):使用变化较大的 X 或 Y 和 1-Z 进行垂直映射
可通过 UVGenerator 选项提供自定义 UV 生成器。
顶点与面构建
几何体分层构建 src/geometries/ExtrudeGeometry.js460-560:
- 背面顶点(z = 0 或在 extrudePath 起点)
- 每个步骤的中间顶点(z = depth * step / steps)
- 正面顶点(z = depth 或在 extrudePath 终点)
- 前后的倒角顶点(如启用)
使用辅助函数添加面:
f3(a, b, c):添加三角形面 src/geometries/ExtrudeGeometry.js694-707f4(a, b, c, d):添加四边形为两个三角形 src/geometries/ExtrudeGeometry.js709-731addVertex(index):将顶点位置推入verticesArraysrc/geometries/ExtrudeGeometry.js733-739
源码: 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: 0 且 bevelEnabled: false 的 ExtrudeGeometry,但针对 2D 用例进行了优化。它对形状进行三角剖分,仅添加一组顶点(无拉伸层)。
内部工具与模式
程序化几何体生成器使用 ShapeUtils 中的通用内部工具,并遵循标准属性构建模式。
ShapeUtils
ExtrudeGeometry 内部用于 2D 形状处理:
ShapeUtils.isClockWise(vertices):确定缠绕顺序以确保逆时针轮廓 src/geometries/ExtrudeGeometry.js145-165ShapeUtils.triangulateShape(contour, holes):耳切法三角剖分以生成面索引 src/geometries/ExtrudeGeometry.js402-453
顶点构建模式
所有程序化生成器遵循此 BufferGeometry 构建模式 src/geometries/ExtrudeGeometry.js74-77:
- 构建平面顶点位置数组(
Float32Array或Array) - 构建面索引数组(用于索引几何体)
- 创建
BufferAttribute对象 - 调用
this.setAttribute('position', new Float32BufferAttribute(verticesArray, 3)) - 调用
this.setAttribute('uv', new Float32BufferAttribute(uvArray, 2)) - 调用
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-202 和 getBevelVec() 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 实例,与渲染管线集成:
- 顶点属性:
position、normal、uv(以及可选的color、tangent) - 绘制组:
addGroup(start, count, materialIndex)支持多材质 src/geometries/ExtrudeGeometry.js626-650 - 包围体:通过
computeBoundingBox()和computeBoundingSphere()计算
渲染系统(见 WebGL 渲染器(传统) 和 现代渲染器架构)消费这些属性以上传数据到 GPU 并执行绘制调用。