核心库
目的与范围
核心库提供构成 Three.js 基础的基础类和抽象。它定义与渲染器无关的 3D 场景表示,包括场景图层次结构、几何体数据结构、材质属性和纹理管理。这一层位于数学原始类型和渲染系统之间,使得能够独立于渲染后端创建和操作 3D 内容。
有关这些核心类使用的数学原始类型信息,请参阅数学原始类型。有关这些核心类如何渲染到屏幕的细节,请参阅渲染架构。
架构概览
核心库由四个主要子系统组成,它们协同工作来表示 3D 场景:
核心库架构
Object3D:场景图基础
Object3D 是 Three.js 中所有可渲染和不可渲染对象的基类。它提供层次变换、事件分发和场景图遍历的公共接口。
Object3D 核心属性与关系
变换系统
Object3D 同时维护欧拉角和四元数表示的变换,两者间自动同步。变换层次结构通过局部和世界矩阵管理:
| 属性 | 类型 | 用途 |
|---|---|---|
| position | Vector3 | 相对于父级的局部位置 |
| rotation | Euler | 作为欧拉角的局部旋转(与四元数同步) |
| quaternion | Quaternion | 作为四元数的局部旋转(与旋转同步) |
| scale | Vector3 | 局部缩放 |
| matrix | Matrix4 | 局部变换矩阵 |
| matrixWorld | Matrix4 | 世界变换矩阵 |
| matrixAutoUpdate | boolean | 从位置/旋转/缩放自动计算局部矩阵 |
| matrixWorldAutoUpdate | boolean | 从层次结构自动计算世界矩阵 |
| pivot | Vector3 | 旋转和缩放变换的枢轴点 |
变换矩阵通过 updateMatrix() 和 updateMatrixWorld() 计算。当 matrixAutoUpdate 为 true 时,每帧从位置、旋转和缩放出局部矩阵。当 matrixWorldAutoUpdate 为 true 时,通过将父级的世界矩阵与局部矩阵相乘来计算世界矩阵。
层次管理
场景图使用父子关系构建。层次操作的关键方法:
| 方法 | 参数 | 用途 |
|---|---|---|
| add(object) | Object3D | 添加子对象,触发 'added' 和 'childadded' 事件 |
| remove(object) | Object3D | 移除子对象,触发 'removed' 和 'childremoved' 事件 |
| removeFromParent() | - | 从此对象的父级中移除 |
| clear() | - | 移除所有子对象 |
| attach(object) | Object3D | 添加子对象同时保持其世界变换 |
| traverse(callback) | Function | 在此对象和所有后代上执行回调 |
| traverseVisible(callback) | Function | 仅在可见对象上执行回调 |
| traverseAncestors(callback) | Function | 在所有祖先上执行回调 |
EventDispatcher 集成
Object3D 扩展 EventDispatcher,提供发布-订阅事件系统。内置事件包括:
added:当对象添加到父级时触发removed:当对象从父级移除时触发childadded:当添加子对象时触发(包含child属性)childremoved:当移除子对象时触发(包含child属性)
BufferGeometry:顶点数据存储
BufferGeometry 使用存储在 BufferAttribute 实例中的类型化数组表示 mesh、线或点几何体。它提供高效的数据传输到 GPU,并支持索引和非索引几何体。
BufferGeometry 数据流
属性管理
几何体属性存储在以属性名为键的字典(attributes)中。常见属性包括:
| 属性 | 项目大小 | 类型 | 用途 |
|---|---|---|---|
| position | 3 | Float32 | 顶点位置(x, y, z) |
| normal | 3 | Float32 | 顶点法线 |
| uv | 2 | Float32 | 纹理坐标 |
| uv1 | 2 | Float32 | 第二组纹理坐标 |
| color | 3 或 4 | Float32 | 顶点颜色(RGB 或 RGBA) |
| tangent | 4 | Float32 | 切线向量(w 分量包含手性) |
| skinIndex | 4 | Uint16 | 蒙皮网格的骨骼索引 |
| skinWeight | 4 | Float32 | 蒙皮网格的骨骼权重 |
属性操作的关键方法:
// 来自 BufferGeometry 类
setAttribute(name, attribute) // 设置属性
getAttribute(name) // 检索属性
deleteAttribute(name) // 移除属性
hasAttribute(name) // 检查属性是否存在索引与非索引几何体
几何体可以是索引的(三角形间共享顶点)或非索引的(每个三角形有唯一顶点):
- 索引几何体:使用
index属性(Uint16 或 Uint32)引用顶点。每三个连续索引定义一个三角形。 - 非索引几何体:当
index为 null 时,每三个连续顶点定义一个三角形。
toNonIndexed() 方法通过将共享顶点复制来将索引几何体转换为非索引格式。
绘制组
组允许使用不同材质渲染几何体的不同部分。每个组指定:
| 属性 | 类型 | 用途 |
|---|---|---|
| start | number | 第一个顶点(非索引)或第一个索引(索引) |
| count | number | 要渲染的顶点或索引数量 |
| materialIndex | number | 材质数组中的索引 |
边界体积计算
BufferGeometry 计算轴对齐边界框(Box3)和边界球(Sphere)用于视锥剔除和相交测试:
computeBoundingBox():从位置属性和形态目标计算boundingBoxcomputeBoundingSphere():使用比边界框更紧密的算法计算boundingSphere
当定义 morphAttributes.position 时,两种方法都考虑形态目标位置。
法线和切线生成
几何体提供从位置数据计算顶点法线和切线的方法:
computeVertexNormals():计算面法线并为共享顶点平均化(索引)或直接分配面法线(非索引)computeTangents():计算用于法线映射的切线向量(需要位置、法线、uv 和索引属性)
BufferAttribute:类型化数组管理
BufferAttribute 包装类型化数组并提供元数据以实现高效的 GPU 传输。它提供访问和操作顶点数据的方法。
BufferAttribute 结构
数据访问方法
BufferAttribute 为常见项目大小提供类型化访问器:
| 方法 | 参数 | 用途 |
|---|---|---|
| getX(index) | index | 获取第一个分量 |
| getY(index) | index | 获取第二个分量 |
| getZ(index) | index | 获取第三个分量 |
| getW(index) | index | 获取第四个分量 |
| setX(index, x) | index, x | 设置第一个分量 |
| setY(index, y) | index, y | 设置第二个分量 |
| setZ(index, z) | index, z | 设置第三个分量 |
| setW(index, w) | index, w | 设置第四个分量 |
| setXY(index, x, y) | index, x, y | 设置两个分量 |
| setXYZ(index, x, y, z) | index, x, y, z | 设置三个分量 |
| setXYZW(index, x, y, z, w) | index, x, y, z, w | 设置四个分量 |
交错属性
InterleavedBuffer 和 InterleavedBufferAttribute 支持将多个属性打包到单个类型化数组中,减少内存开销并提高缓存一致性:
每个 InterleavedBufferAttribute 引用具有 offset 和 itemSize 的共享缓冲区,允许高效的数据布局:[x,y,z,nx,ny,nz,u,v, x,y,z,nx,ny,nz,u,v, ...]
实例化属性
InstancedBufferAttribute 扩展 BufferAttribute 用于实例化渲染,其中每个实例可以有唯一的属性值:
meshPerAttribute:定义每个属性值使用多少实例(通常为 1)- 与
InstancedBufferGeometry一起使用,用于渲染具有变化属性的几何体多个副本
InstancedInterleavedBuffer 为交错数据提供相同功能。
材质:表面外观
Material 是所有材质的抽象基类,定义控制表面在渲染时外观的属性。它为混合、深度测试、模板操作和自定义着色器钩子提供公共接口。
材质属性类别
材质属性组
混合与透明度
| 属性 | 类型 | 默认值 | 用途 |
|---|---|---|---|
| blending | Constant | NormalBlending | 混合模式(Normal, Additive, Subtractive, Multiply, Custom, None) |
| transparent | boolean | false | 材质是否透明(影响渲染顺序) |
| opacity | number | 1.0 | 材质不透明度(0.0 = 完全透明, 1.0 = 不透明) |
| blendSrc | Constant | SrcAlphaFactor | 源混合因子(需要 CustomBlending) |
| blendDst | Constant | OneMinusSrcAlphaFactor | 目标混合因子(需要 CustomBlending) |
| blendEquation | Constant | AddEquation | 混合方程(Add, Subtract, ReverseSubtract, Min, Max) |
深度与模板
| 属性 | 类型 | 默认值 | 用途 |
|---|---|---|---|
| depthTest | boolean | true | 启用深度测试 |
| depthWrite | boolean | true | 写入深度缓冲区 |
| depthFunc | Constant | LessEqualDepth | 深度比较函数 |
| stencilWrite | boolean | false | 启用模板操作 |
| stencilFunc | Constant | AlwaysStencilFunc | 模板比较函数 |
| stencilRef | number | 0 | 模板测试的参考值 |
材质回调
材质提供在渲染期间自定义的钩子:
| 回调 | 参数 | 用途 |
|---|---|---|
| onBeforeRender | renderer, scene, camera, geometry, object, group | 在渲染对象前调用 |
| onBeforeCompile | shaderobject, renderer | 编译前修改着色器源代码(仅 WebGLRenderer) |
| customProgramCacheKey | - | 返回字符串键用于着色器缓存标识 |
onBeforeCompile 回调为 WebGLRenderer 启用着色器修改:
material.onBeforeCompile = function(shader, renderer) {
// 修改 shader.vertexShader 或 shader.fragmentShader
// 访问 shader.uniforms
}纹理:图像数据管理
Texture 封装图像数据和材质的采样参数。它使用 Source 对象在多个纹理间共享图像数据。
纹理结构与关系
纹理坐标变换
纹理通过偏移、重复、中心和旋转支持 UV 变换:
offset:UV 空间中的平移repeat:UV 空间中的缩放(值 > 1 平铺纹理)center:UV 空间中的旋转中心rotation:弧度单位的旋转角度
当 matrixAutoUpdate 为 true 时,这些属性用于通过 updateMatrix() 计算 matrix,应用变换:matrix.setUvTransform(offset.x, offset.y, repeat.x, repeat.y, rotation, center.x, center.y)
纹理源共享
Source 类 (src/textures/Source.js) 保存实际图像数据,可在多个 Texture 实例间共享。这对以下情况很有用:
- 从同一图像创建具有不同采样参数的多个纹理
- 实现纹理图集,其中多个纹理引用相同源但具有不同的 UV 变换
序列化与加载
核心库包含用于从 JSON 格式反序列化 Three.js 对象的加载器,支持具有几何体、材质、纹理、动画和骨骼层次结构的完整场景图。
ObjectLoader 数据流
ObjectLoader 流水线
ObjectLoader 分阶段解析 JSON 序列化场景:
- 形状 (src/loaders/ObjectLoader.js270-288):解析挤出几何体的 2D 形状
- 几何体 (src/loaders/ObjectLoader.js321-368):使用
BufferGeometryLoader或程序化几何体类解析几何数据 - 图像 (src/loaders/ObjectLoader.js423-633):通过
ImageLoader加载图像或反序列化内嵌数据纹理 - 纹理 (src/loaders/ObjectLoader.js635-740):使用采样参数创建
Texture实例 - 材质 (src/loaders/ObjectLoader.js371-399):使用
MaterialLoader解析材质 - 对象 (src/loaders/ObjectLoader.js743-1045):递归构建 Object3D 层次结构
- 骨骼 (src/loaders/ObjectLoader.js290-318):解析蒙皮网格的骨骼数据
- 绑定 (src/loaders/ObjectLoader.js1047-1108):将骨骼附加到网格并解析光源目标
MaterialLoader
MaterialLoader 从 JSON 反序列化材质属性,创建具体材质类的实例:
// createMaterialFromType() 识别的材质类型
MeshBasicMaterial, MeshLambertMaterial, MeshPhongMaterial,
MeshStandardMaterial, MeshPhysicalMaterial, MeshToonMaterial,
MeshNormalMaterial, MeshMatcapMaterial, MeshDepthMaterial,
MeshDistanceMaterial, LineBasicMaterial, LineDashedMaterial,
PointsMaterial, SpriteMaterial, ShaderMaterial, RawShaderMaterial,
ShadowMaterial加载器设置材质属性并从纹理字典解析纹理引用。
序列化格式
Object3D.toJSON() 和 Material.toJSON() 将对象序列化为与 ObjectLoader 兼容的 JSON 格式:
| 元数据 | 内容 |
|---|---|
| metadata.version | 4.7 |
| metadata.type | 'Object' 或 'Material' |
| metadata.generator | 'Object3D.toJSON' 或 'Material.toJSON' |
序列化捕获:
- 对象层次结构和变换
- 几何体与材质引用(通过 UUID)
userData中的自定义属性- 动画剪辑
SkinnedMesh的骨骼绑定
WebGL 资源管理
虽然核心库与渲染器无关,但它通过专门的资源管理系统与 WebGL 接口:
WebGL 资源管理流
WebGLGeometries
WebGLGeometries 管理几何体资源的生命周期:
- 通过几何体 ID 使用
WeakMap跟踪几何体 - 通过
EventDispatcher'dispose' 事件注册处置处理器 - 通过
WebGLAttributes更新属性缓冲区 - 为线框渲染模式生成线框索引
- 管理
InstancedBufferGeometry实例计数
WebGLAttributes
WebGLAttributes 管理 BufferAttribute 数据的 WebGL 缓冲区对象:
- 使用
gl.createBuffer()创建 VBO 并通过gl.bufferData()上传数据 - 使用
updateRanges通过gl.bufferSubData()增量更新缓冲区 - 合并相邻更新范围以最小化 GPU 命令开销
- 将 TypedArray 类型映射到 WebGL 常量(FLOAT, HALF_FLOAT, UNSIGNED_SHORT 等)
WebGLBindingStates
WebGLBindingStates 管理顶点数组对象(VAO)以缓存属性绑定:
- 为每个(对象, 几何体, 程序, 材质)组合创建唯一 VAO
- 缓存顶点属性指针配置
- 通过绑定缓存的 VAO 减少状态更改
- 处理
InstancedMesh的实例化属性 - 跟踪线框与实体几何体变体
WebGLObjects
WebGLObjects 协调每帧的几何体和属性更新:
- 使用帧跟踪每帧更新一次几何体
- 更新
InstancedMesh的实例矩阵 - 触发
SkinnedMesh的骨骼更新 - 管理实例化网格资源的处置
WebGLProperties
WebGLProperties 使用 WeakMap 提供通用属性存储,允许渲染器特定的元数据附加到核心对象而无需修改其类定义。
与其他系统的关系
核心库作为其他 Three.js 系统的基础:
| 系统 | 关系 |
|---|---|
| 数学原始类型(#2.1) | 核心库使用 Vector3, Matrix4, Quaternion 等进行变换 |
| 常量(#2.2) | 核心库引用混合模式、纹理格式等的常量 |
| 渲染(#3) | 渲染器消费核心库对象以生成 GPU 命令 |
| 资源管线(#4) | 加载器从外部文件格式创建核心库对象 |
| 交互系统(#5) | 射线检测和动画系统在核心库场景图上操作 |