首页
/ three.js OctahedronGeometry 八面体几何体完全指南:构造参数、detail 细分原理与源码剖析

three.js OctahedronGeometry 八面体几何体完全指南:构造参数、detail 细分原理与源码剖析

2026-09-07 22:01:05作者:江焘钦

在 three.js 中,OctahedronGeometry(八面体几何体)是内置的“柏拉图立体”几何体家族成员之一,它基于 PolyhedronGeometry 实现,用于生成由 8 个全等三角形面组成的正八面体网格。它最常见的用途是作为宝石、水晶、能量结晶等硬朗风格物体的低多边形基础模型;当把 detail 参数调大后,八面体会被逐层细分并投影到球面上,从而平滑地逼近一个球体。本文将围绕 OctahedronGeometry 官方文档 的完整内容,结合 核心源码、基类实现与单元测试,讲解其构造参数、继承体系、底层顶点数据、细分算法、序列化与编辑器/示例中的实际用法,帮助你彻底掌握这一几何体并能直接在项目中落地使用。

一、什么是 OctahedronGeometry

正八面体(Octahedron)是一个由 8 个等边三角形面围成的三维凸多面体,拥有 6 个顶点、8 个面、12 条棱,它同时也是立方体的对偶多面体(将立方体的 6 个面心相连即得到八面体)。在 three.js 官方文档 中,它的继承链被标注为:

EventDispatcher → BufferGeometry → PolyhedronGeometry → OctahedronGeometry

也就是说,OctahedronGeometry 并不直接构建顶点缓冲,而是把八面体的基础几何数据交给父类 PolyhedronGeometry 完成“顶点投影到球面 + 按需细分 + 生成 UV + 填充 position/normal/uv 缓冲属性”的全部工作,自身只负责提供八面体特有的顶点与三角面索引,以及参数记录与 JSON 反序列化工厂方法。这一点从源码即可确认:OctahedronGeometry 类的构造器只做三件事——定义基础顶点/索引、调用 super(...)、设置 typeparameters(见 src/geometries/OctahedronGeometry.js)。

二、快速上手:创建并渲染一个八面体

官方文档给出了最精简的核心用法,仅需三步:创建几何体 → 创建材质 → 组合成 Mesh 加入场景:

const geometry = new THREE.OctahedronGeometry();
const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
const octahedron = new THREE.Mesh( geometry, material );
scene.add( octahedron );

若需要一份可直接运行的完整示例,可参照官方 几何体浏览器演示场景(该页面内的 OctahedronGeometry 条目与本文档互通),或阅读经典示例 examples/webgl_geometries.html,其中以 new THREE.OctahedronGeometry( 75 ) 的方式创建了一个半径为 75 的八面体并加入示例场景:

object = new THREE.Mesh( new THREE.OctahedronGeometry( 75 ), material );

下面是一个稍完整的、可渲染的最小示例骨架(包含渲染器、相机与坐标定位),便于你直接在页面中验证效果:

import * as THREE from 'three';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.z = 5;

const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

// 使用 MeshStandardMaterial 可更好地体现八面体棱角分明的明暗面
const geometry = new THREE.OctahedronGeometry( 1 );
const material = new THREE.MeshStandardMaterial( { color: 0x00aaff, flatShading: true } );
const octahedron = new THREE.Mesh( geometry, material );
scene.add( octahedron );

function animate() {
	requestAnimationFrame( animate );
	octahedron.rotation.x += 0.005;
	octahedron.rotation.y += 0.01;
	renderer.render( scene, camera );
}
animate();

提示:OctahedronGeometry 返回的是 BufferGeometry 实例,可直接应用 MeshPointsLineSegments,并支持所有 BufferGeometry 的变换与属性操作。

三、构造函数与参数详解

3.1 签名与默认值

new OctahedronGeometry( radius : number, detail : number )

两个参数均有默认值,均可不传(源码中声明为 radius = 1, detail = 0,见 OctahedronGeometry 源码)。参数含义如下表:

参数 类型 默认值 说明
radius number 1 八面体外接半径,即所有顶点到原点(物体局部坐标系中心)的距离
detail number 0 细分层级。大于 0 时会在每个三角面上追加中间顶点并投影到球面,使结果不再是严格意义上的八面体,而是趋近球体;层级越高,面越多、越平滑

官方文档对 detail 给出了一个很关键的提醒:“Setting this to a value greater than 0 adds vertices making it no longer a octahedron.” 原因在于 PolyhedronGeometry 的细分流程会把新增顶点归一化后按 radius 重新投影到外接球面上(详见下文“细分原理”),所以 detail > 0 时得到的实际上是“球化八面体”,而非多面体。

3.2 取值建议与组合

  • detail = 0:经典正八面体,8 个面、24 个顶点(每面独立 3 顶点,非索引)。适合晶体、骰子风格的低多边形造型,或作为 flatShading 的展示对象。
  • detail = 1:把每个三角形面细分为 4 个小三角形,再投影到球面,得到 32 个面。
  • detail = 2:进一步细分(64 个面),外观已接近圆润球体,常用于替代 SphereGeometry 的低多边形近似,或在需要以“八面体为基础”再做顶点扰动变形时使用。

radius 的典型取值没有限制,直接决定几何体的尺寸;例如官方示例中的 75 是为配合特定的相机距离与场景比例而设定,实际项目中通常与相机、灯光、单位制一同规划。

四、内部实现:八面体的基础顶点数据

4.1 基础顶点与三角面

OctahedronGeometry 并非用几何公式实时计算,而是直接内嵌了八面体的 6 个基础顶点(每个顶点恰好落在三个坐标轴的正负方向上)与 8 个三角形面的索引(见 源码 L26-L35):

const vertices = [
	1, 0, 0,    -1, 0, 0,    0, 1, 0,
	0, -1, 0,    0, 0, 1,    0, 0, -1
];

const indices = [
	0, 2, 4,    0, 4, 3,    0, 3, 5,
	0, 5, 2,    1, 2, 5,    1, 5, 3,
	1, 3, 4,    1, 4, 2
];

6 个基础顶点依次为:(1,0,0)(-1,0,0)(0,1,0)(0,-1,0)(0,0,1)(0,0,-1),它们单位化后长度均为 1,处于单位球面上;随后通过 super( vertices, indices, radius, detail ) 交给父类处理。8 条三角形索引记录构成 8 个面,每个面恰好从三个不同轴方向各取一个顶点(如 0,2,4 连接 X+、Y+、Z+ 三个方向的顶点),这正是正八面体“每个面横跨三条轴”的几何特征。同时注意这里传给父类的 indices 并非最终 BufferGeometry 的索引缓冲,而仅作为“描述基础多面体拓扑”的输入。

4.2 顶点数据的扁平化细节

代码中 verticesindices 均为扁平数组vertices 每 3 个元素构成一个顶点,indices 每 3 个元素构成一个三角形(索引指向 vertices 的下标)。父类 PolyhedronGeometrygetVertexByIndex 内部通过 index * 3 计算偏移取出顶点坐标(见 PolyhedronGeometry 源码)。

五、细节再挖一层:父类 PolyhedronGeometry 如何把八面体变成网格

理解 OctahedronGeometry 的运行效果,关键在于其父类的三步管线(见 src/geometries/PolyhedronGeometry.js):

  1. 细分(subdivide / subdivideFace:遍历每条三角索引记录,把每个面按 detail 进行网格化插值。算法的核心结构是 cols = detail + 1:对顶点 abc 围成的三角形,先在 a→cb→c 方向上做插值得到层线,再在每条层线上切出小三角形(偶数步推入一类三角形、奇数步推入相邻的翻转三角形),最终把扁平顶点逐面 push 进 vertexBufferdetail = 0cols = 1,即每个输入三角面原样输出一个三角形;detail 每 +1,面上网格密度显著提升(见 subdivideFace 实现)。
  2. 半径投影(applyRadius:遍历 vertexBuffer 中的每个顶点,先 normalize()multiplyScalar(radius)。这一步保证即便细分产生了大量中间点,所有顶点仍精确落在以原点为中心、radius 为半径的球面上(见 applyRadius 实现)。这是“detail>0 后八面体变球体”的根本原因。
  3. 生成 UV(generateUVs:依据每个顶点的方位角 azimuth(绕 Y 轴)与倾角 inclination(相对 XZ 平面)把球面坐标映射为 u/v(见 L187-L207),并调用 correctUVs/correctSeam 修复横跨纹理接缝(seam)的三角形 UV 跳变问题(注释中提及 issue #3269,见 correctSeam)。

生成结束后,父类以**非索引(non-indexed)**方式一次性设置三个缓冲属性:

this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );

法线的处理策略同样与 detail 相关(见 L66-L74):

  • detail === 0:调用 computeVertexNormals() 计算平坦法线(flat normals)——每个面的三个顶点法线一致,因此光照下面与面之间棱角分明;
  • detail > 0:顶点法线已趋近球面法线方向,因此改用 normalizeNormals() 得到平滑法线(smooth normals)

这也是为什么 detail = 0 的八面体在光照下呈现出清晰的棱面质感,而高 detail 结果则呈现光滑球体观感。

六、属性说明

6.1 .parameters : Object

OctahedronGeometry 在构造后会把入参记录到 parameters 属性中:

this.parameters = {
	radius: radius,
	detail: detail
};

其语义在官方文档中明确为:“保存用于生成该几何体的构造参数。实例化后的任何修改都不会改变几何体本身。”也就是说,若想在运行时改变八面体尺寸或细分度,正确做法是丢弃旧几何体、用新参数重新 new THREE.OctahedronGeometry(...)(或调用几何体的 dispose() 并替换),而不是修改 .parameters

此处有一个值得一提的继承细节:官方文档将其标注为对 [PolyhedronGeometry#parameters](https://gitcode.com/GitHub_Trending/th/three.js/blob/22e5760357778d34c4578bfb00bf22e50c30d6b7/docs/pages/PolyhedronGeometry.html.md?utm_source=gitcode_repo_files)Overrides(覆盖)。对比可知,父类 PolyhedronGeometry.parameters 会额外保存 verticesindices(见 PolyhedronGeometry L36-L41),而 OctahedronGeometry 重新定义了只含 radiusdetailparameters,对外隐藏了内部的基础顶点/索引,这使 .parameters 的结构更贴近“用户可理解的构造参数”。此外父类实现了 copy( source ),会以 Object.assign 方式深拷贝一份源几何体的 parameters(见 PolyhedronGeometry L323-L331),因此克隆得到的八面体在共享缓冲数据语义上依旧安全。

6.2 其它继承属性

  • .type:实例的 type 被设为字符串 'OctahedronGeometry'(见 源码 L39),供序列化、编辑器识别与加载器反序列化使用。
  • 其余的 boundingSphereboundingBox、属性缓冲等均由 BufferGeometry 提供;可通过 geometry.computeBoundingSphere() 等标准 API 进一步处理。

七、静态方法与序列化往返

7.1 .fromJSON( data : Object ) : OctahedronGeometry

static fromJSON( data ) {
	return new OctahedronGeometry( data.radius, data.detail );
}

这是从序列化 JSON 对象重建实例的工厂方法(见 源码 L62-L66)。data 为描述几何体的 JSON 对象,方法返回一个新实例。其典型工作流是配合 BufferGeometry/场景的序列化机制:几何体在 toJSON() 阶段把 typeparameters 一并写出,加载端依据 type === 'OctahedronGeometry' 找到本类,再以 .fromJSON() 恢复出 radiusdetail 并重建几何体。由于 fromJSON 只依赖 data.radiusdata.detail 两个字段,这意味着导出的 JSON 中只要保留这两个核心参数即可无损还原几何外观。

八、在编辑器与真实示例中的落地形态

OctahedronGeometry 不仅可作为库函数使用,还深度集成在 three.js 官方编辑器与示例中,可作为开发者的参考范式:

  • 官方编辑器「添加 → 网格/几何体」菜单:默认以 new THREE.OctahedronGeometry( 1, 0 ) 创建基础八面体(见 editor/js/Menubar.Add.js)。
  • 编辑器属性面板OctahedronGeometry 的参数面板(见 editor/js/Sidebar.Geometry.OctahedronGeometry.js)对 radius 使用 UINumber(可输入小数),对 detail 使用 UIInteger 并设置范围 [0, Infinity),从 UI 层面印证了两个参数的默认语义:radius 允许任意正实数,detail 必须是大于等于 0 的整数。修改参数后会通过 SetGeometryCommand 重新构造几何体并记入撤销栈,这与“修改 parameters 不会改变几何体、需重新实例化”的文档约束完全一致。
  • 官方示例examples/webgl_geometries.html 中使用 new THREE.OctahedronGeometry( 75 ) 展示了默认八面体在场景中的外观。

九、质量保障:单元测试如何校验行为

仓库中的单元测试 test/unit/src/geometries/OctahedronGeometry.tests.js 覆盖了本类的三类关键契约,可作为你理解其行为边界的最直接佐证:

  1. 继承关系:断言 new OctahedronGeometry()PolyhedronGeometry 的实例(instanceoftrue),验证了文档声明的继承链。
  2. 实例化与类型标识:断言对象可成功创建,且 object.type === 'OctahedronGeometry'
  3. 标准几何测试:以 radius = 10detail 未传(采用默认值 0)以及两者都传入的三种构造形态,通过 runStdGeometryTests 跑全套标准几何断言(位置/法线/UV 缓冲结构、包围盒/包围球计算、克隆与序列化往返等通用契约)。

运行该组测试的方式与仓库其它单元测试一致(基于 QUnit 的 test/unit 套件),此处不展开。

十、总结与实践建议

最后,把本文要点浓缩为可直接落地的建议:

  1. 默认形态new THREE.OctahedronGeometry() 生成半径 1、8 个三角面、带平坦法线的标准正八面体,顶点全部位于以原点为中心的单位球面上。
  2. 参数规律radius 等比缩放整体尺寸;detail 每提升 1 级,每个三角面细分成 4 倍数量的子三角形并投影回球面,因此 detail > 0 时产物更接近球体而非八面体——若追求“圆润的低多边形”,可从 detail = 1~2 起步尝试。
  3. 性能与形态取舍detail = 0 时生成非索引网格、24 个顶点,内存开销极低;高 detail 时顶点数快速上升,请按目标设备与可视需求选择层级,避免不必要的过度细分。
  4. 动态修改:不要试图改写 .parameters;需要改尺寸或平滑度时,重建几何体并记得对旧实例调用 dispose() 释放 GPU 缓冲。
  5. 序列化:依赖 .toJSON() / .fromJSON() 即可无损保存与还原 radiusdetail 两个参数;手动构造 JSON 时也只需提供这两个字段。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388