关于 threejs-syntax-geometries
threejs-syntax-geometries 是面向 Three.js 开发者的几何体参考,讲解网格数据的创建与管理,涵盖 BufferGeometry、属性、内置形状、实例化和资源处理。
主要功能
- 01BufferGeometry 与 BufferAttribute API
- 02内置几何体目录
- 03自定义路径与挤出
- 04InstancedMesh 用法
- 05几何体更新与释放
适用场景
- 01创建自定义网格
- 02选择内置基础形状
- 03高效渲染重复对象
- 04安全更新顶点数据
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ impertio-studio/ three.js-claude-skill-package --skill threejs-syntax-geometries安装后在 Claude Code 中输入/threejs-syntax-geometries确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
.gitkeepreferences/anti-patterns.mdexamples.mdmethods.md详细介绍
threejs-syntax-geometries
快速参考
BufferGeometry:核心属性
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
attributes | Object | {} | 由具名 BufferAttribute 实例构成的哈希映射 |
index | BufferAttribute | null | null | 用于索引渲染的索引缓冲区 |
morphAttributes | Object | {} | 变形目标属性数组 |
morphTargetsRelative | Boolean | false | 如果为 true,变形数据表示相对偏移量 |
groups | Array | [] | 用于多材质的 { start, count, materialIndex } |
drawRange | Object | { start: 0, count: Infinity } | 要渲染的几何体部分 |
boundingBox | Box3 | null | null | 缓存值 — 在调用 computeBoundingBox() 前为 null |
boundingSphere | Sphere | null | null | 缓存值 — 在调用 computeBoundingSphere() 前为 null |
BufferGeometry:关键方法
| 方法 | 返回值 | 描述 |
|---|---|---|
setAttribute(name, attr) | this | 添加或替换具名属性 |
getAttribute(name) | BufferAttribute | 按名称获取属性 |
deleteAttribute(name) | this | 移除具名属性 |
hasAttribute(name) | boolean | 检查属性是否存在 |
setIndex(attr) | — | 设置索引缓冲区 |
addGroup(start, count, materialIndex?) | — | 为多材质定义渲染组 |
clearGroups() | — | 移除所有组 |
setDrawRange(start, count) | — | 限定渲染范围 |
computeVertexNormals() | — | 根据面拓扑计算平滑法线 |
computeTangents() | — | 计算切线向量(需要 position、normal、uv 和 index) |
computeBoundingBox() | — | 计算并缓存 AABB |
computeBoundingSphere() | — | 计算并缓存包围球 |
toNonIndexed() | 新几何体 | 创建非索引副本,并复制顶点 |
translate(x, y, z) | this | 原地平移顶点位置 |
rotateX/Y/Z(radians) | this | 原地旋转顶点位置 |
scale(x, y, z) | this | 原地缩放顶点位置 |
center() | this | 将几何体中心移至原点 |
dispose() | — | 释放 GPU 资源 |
BufferAttribute:构造函数和属性
import * as THREE from 'three';
new THREE.BufferAttribute(array: TypedArray, itemSize: number, normalized?: boolean)
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
array | TypedArray | — | 底层数据 |
itemSize | number | — | 每个顶点的值数量(1=标量,2=UV,3=位置,4=RGBA) |
count | number | 计算得出 | array.length / itemSize |
needsUpdate | boolean | false | 设置为 true,将更改上传到 GPU |
usage | number | StaticDrawUsage | GPU 使用提示 |
类型化便捷类
| 类 | 底层类型 | 用途 |
|---|---|---|
Float32BufferAttribute | Float32Array | 位置、法线、UV(最常用) |
Float16BufferAttribute | Float16Array | 内存优化属性 |
Uint16BufferAttribute | Uint16Array | 索引缓冲区(顶点数 <65536) |
Uint32BufferAttribute | Uint32Array | 索引缓冲区(顶点数 >65536) |
Uint8BufferAttribute | Uint8Array | 字节颜色(使用 normalized=true) |
Int8/Int16/Int32BufferAttribute | 对应数组 | 有符号整数数据 |
使用提示
| 常量 | 使用场景 |
|---|---|
THREE.StaticDrawUsage | 数据仅上传一次,读取多次(默认) |
THREE.DynamicDrawUsage | 数据频繁更新(粒子、动画顶点) |
THREE.StreamDrawUsage | 数据每帧更新并读取一次 |
关键警告
绝不要在通过 setX/setXY/setXYZ 或直接写入数组修改 BufferAttribute 数据后,忘记设置 attribute.needsUpdate = true。如果没有此标志,修改将无法传到 GPU。
绝不要假设 boundingBox 或 boundingSphere 会自动填充。在显式调用 computeBoundingBox() / computeBoundingSphere() 之前,它们都是 null。
如果需要光照,构建自定义几何体后务必调用 computeVertexNormals()。如果没有法线,MeshStandardMaterial 和其他受光照影响的材质会渲染为黑色。
从场景中永久移除几何体时,务必调用 geometry.dispose()。未释放会导致 GPU 内存泄漏。垃圾回收器不会释放 GPU 端的缓冲区。
绝不要在动画循环中调用 translate()、rotateX()、scale() 或其他原地变换方法。这些方法会永久修改实际顶点数据。运行时变换请使用 mesh.position、mesh.rotation 和 mesh.scale。
如果计划每帧更新属性数据,务必在首次渲染前将 usage 设置为 DynamicDrawUsage。初次上传后再更改 usage 对某些 GPU 驱动程序无效。
在 InstancedMesh 上调用 setMatrixAt() 后,绝不要忘记设置 instanceMatrix.needsUpdate = true。如果没有此标志,所有实例都会渲染在原点。
索引几何体与非索引几何体
| 方面 | 索引几何体 | 非索引几何体 |
|---|---|---|
| 内存 | 较低(顶点共享) | 较高(顶点重复) |
| GPU 缓存 | 更好(顶点复用) | 不复用 |
| 平面着色 | 需要重复法线 | 每个面自然拥有独立法线 |
| 线框 | 边缘整洁 | 可能显示对角线 |
对于顶点共享的平滑着色网格,务必使用索引几何体。只有在需要逐面属性(具有唯一法线的平面着色)时,才使用 geometry.toNonIndexed()。
全部 21 种内置几何体
基本体
| 几何体 | 关键参数 |
|---|---|
BoxGeometry | (width=1, height=1, depth=1, wSeg=1, hSeg=1, dSeg=1) |
SphereGeometry | (radius=1, wSeg=32, hSeg=16, phiStart, phiLen, thetaStart, thetaLen) |
PlaneGeometry | (width=1, height=1, wSeg=1, hSeg=1) |
CylinderGeometry | (radTop=1, radBot=1, height=1, radSeg=32, hSeg=1, open, thetaStart, thetaLen) |
ConeGeometry | (radius=1, height=1, radSeg=32, hSeg=1, open, thetaStart, thetaLen) |
CapsuleGeometry | (radius=1, length=1, capSeg=4, radSeg=8) |
TorusGeometry | (radius=1, tube=0.4, radSeg=12, tubSeg=48, arc=2PI) |
TorusKnotGeometry | (radius=1, tube=0.4, tubSeg=64, radSeg=8, p=2, q=3) |
CircleGeometry | (radius=1, seg=32, thetaStart=0, thetaLen=2PI) |
RingGeometry | (inner=0.5, outer=1, thetaSeg=32, phiSeg=1, thetaStart, thetaLen) |
多面体
所有几何体均接受 (radius=1, detail=0)。detail 控制细分级别。
| 几何体 | 基础面数 |
|---|---|
TetrahedronGeometry | 4 |
OctahedronGeometry | 8 |
DodecahedronGeometry | 12 |
IcosahedronGeometry | 20 |
PolyhedronGeometry | 自定义(vertices, indices, radius, detail) |
基于路径的几何体
| 几何体 | 描述 |
|---|---|
ExtrudeGeometry(shapes, options) | 将 2D Shape 拉伸为 3D |
ShapeGeometry(shapes, curveSegments=12) | 从 Shape 创建平面 2D 几何体 |
LatheGeometry(points, segments=12, phiStart, phiLength) | 绕 Y 轴旋转 2D 轮廓 |
TubeGeometry(path, tubSeg=64, radius=1, radSeg=8, closed) | 沿 Curve3 创建管体 |
实用工具
| 几何体 | 描述 |
|---|---|
EdgesGeometry(geometry, thresholdAngle=1) | 角度大于阈值的边(整洁的轮廓) |
WireframeGeometry(geometry) | 所有三角形边(调试可视化) |
ExtrudeGeometry 选项
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
depth | number | 1 | 挤出深度 |
steps | number | 1 | 沿深度方向的细分步数 |
bevelEnabled | boolean | true | 启用边缘倒角 |
bevelThickness | number | 0.2 | 向形状内部延伸的倒角深度 |
bevelSize | number | bevelThickness - 0.1 | 倒角与轮廓之间的距离 |
bevelOffset | number | 0 | 倒角相对于边缘的偏移量 |
bevelSegments | number | 3 | 倒角细分精度 |
curveSegments | number | 12 | 曲线上的点数 |
extrudePath | Curve | undefined | 沿其挤出的 3D 路径 |
UVGenerator | Object | WorldUVGenerator | 自定义 UV 生成 |
Shape 类:2D 路径绘制
import * as THREE from 'three';
const shape = new THREE.Shape();
shape.moveTo(x, y); // Start new subpath
shape.lineTo(x, y); // Straight line
shape.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y); // Cubic Bezier
shape.quadraticCurveTo(cpx, cpy, x, y); // Quadratic Bezier
shape.splineThru(points); // Smooth spline through Vector2[]
shape.arc(aX, aY, radius, startAngle, endAngle, cw); // Relative arc
shape.absarc(aX, aY, radius, startAngle, endAngle, cw); // Absolute arc
// Holes
const holePath = new THREE.Path();
holePath.absarc(0, 0, 0.5, 0, Math.PI * 2);
shape.holes.push(holePath);
变形目标
import * as THREE from 'three';
// Define morph target positions
const morphPositions = new Float32Array([/* ... */]);
geometry.morphAttributes.position = [
new THREE.BufferAttribute(morphPositions, 3)
];
// Control on the mesh
mesh.morphTargetInfluences[0] = 0.5; // 50% blend toward morph target 0
// Named morph targets (from glTF)
mesh.morphTargetDictionary; // { "smile": 0, "frown": 1 }
当变形数据表示偏移量而非绝对位置时,请设置 geometry.morphTargetsRelative = true。
InstancedMesh
import * as THREE from 'three';
const mesh = new THREE.InstancedMesh(geometry, material, count);
| 属性 | 类型 | 描述 |
|---|---|---|
instanceMatrix | InstancedBufferAttribute | 4x4 矩阵(每个实例 16 个浮点数) |
instanceColor | InstancedBufferAttribute | null | 每个实例的 RGB 颜色(首次调用 setColorAt 时创建) |
count | number | 实例数量(构造后只读) |
| 方法 | 描述 |
|---|---|
setMatrixAt(index, matrix4) | 设置实例的变换 |
getMatrixAt(index, matrix4) | 将变换读取到目标对象中 |
setColorAt(index, color) | 设置实例的颜色 |
getColorAt(index, color) | 读取实例的颜色 |
性能指南
| 实例数量 | 建议 |
|---|---|
| < 10 | 使用独立的 Mesh 对象 |
| 10 - 100 | 两种方式均可;根据具体情况进行性能分析 |
| 100 - 10,000 | 始终使用 InstancedMesh |
| > 10,000 | 使用带空间细分的 InstancedMesh 或 BatchedMesh(r160+) |
自定义每实例属性
import * as THREE from 'three';
const phases = new Float32Array(count);
for (let i = 0; i < count; i++) phases[i] = Math.random();
mesh.geometry.setAttribute('aPhase', new THREE.InstancedBufferAttribute(phases, 1));
// Access in vertex shader: attribute float aPhase;
使用组实现多材质
import * as THREE from 'three';
geometry.addGroup(0, 6, 0); // First 6 indices -> material[0]
geometry.addGroup(6, 6, 1); // Next 6 indices -> material[1]
const mesh = new THREE.Mesh(geometry, [materialA, materialB]);
InterleavedBuffer
对于大型网格(10,000+ 个顶点),为获得最佳 GPU 缓存性能:
import * as THREE from 'three';
const stride = 8; // 3 (position) + 3 (normal) + 2 (uv)
const buffer = new THREE.InterleavedBuffer(new Float32Array(vertexCount * stride), stride);
geometry.setAttribute('position', new THREE.InterleavedBufferAttribute(buffer, 3, 0));
geometry.setAttribute('normal', new THREE.InterleavedBufferAttribute(buffer, 3, 3));
geometry.setAttribute('uv', new THREE.InterleavedBufferAttribute(buffer, 2, 6));
当各属性单独更新时,始终使用独立缓冲区。仅当所有属性均为静态或一同更新时,才使用交错缓冲区。
释放规则
- 从场景中永久移除几何体时,始终调用
geometry.dispose() - 共享几何体(由多个网格使用):仅在所有网格都移除后释放
- 内置几何体:移除使用它的网格时释放
- JavaScript 垃圾回收器不会释放 GPU 端的顶点缓冲区
参考链接
- references/methods.md — BufferGeometry、BufferAttribute、InstancedMesh 的完整 API 签名
- references/examples.md — 自定义几何体、实例化和挤出的可运行代码示例
- references/anti-patterns.md — 在 Three.js 中使用几何体时应避免的做法