
three.js TorusGeometry 完全指南甜甜圈环体几何的创建、参数解析与源码实现【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.jsTorusGeometry 是 three.js 内置的“甜甜圈/轮胎”形环体几何类通过指定主半径与管半径即可快速生成用于几何演示、后处理遮罩、拖拽与编辑手柄gizmo、体积水波边界等多种场景的基础网格。本篇围绕官方文档的核心脉络结合 TorusGeometry 源码 与 单元测试完整讲解其继承体系、全部构造参数、顶点/法线/UV 生成原理、属性、静态工厂方法及实战用法帮助你既会用 API也看得懂底层实现。一、类概览与继承关系在 three.js 中所有内置几何体都属于“缓冲几何体”BufferGeometry体系。TorusGeometry 位于继承链的最末端EventDispatcher → BufferGeometry → TorusGeometryEventDispatcher事件分发器为几何体提供addEventListener、dispatchEvent等事件能力BufferGeometry缓冲几何基类负责管理顶点索引与各种BufferAttribute属性提供setIndex、setAttribute、computeBoundingSphere等通用接口TorusGeometry本身只在构造阶段负责“参数化生成一张环形网格”之后一切渲染、裁剪、射线检测等能力均由父类承担。这一继承关系可以在单元测试中得到直接印证test/unit/src/geometries/TorusGeometry.tests.js中通过assert.strictEqual( object instanceof BufferGeometry, true, TorusGeometry extends from BufferGeometry )断言子类关系同时断言实例的type属性为字符串TorusGeometry用于序列化时的类型识别。类定义中通过augments BufferGeometry标注继承关系并挂载了一个示例场景标注demo对应仓库中的 geometry-browser 场景页可在该场景中以交互方式对比查看环体与其他基础几何体的形状差异。二、构造函数与全部参数详解new TorusGeometry( radius, tube, radialSegments, tubularSegments, arc, thetaStart, thetaLength )从 源码 可见七个参数全部带有默认值因此new THREE.TorusGeometry()本身也是合法的参数类型默认值含义与约束radiusnumber1环体主半径从环体中心到管道tube中心线的距离即“甜甜圈”回转半径tubenumber0.4管半径管道的粗细必须小于radius否则管道中心线将越过环体轴线产生自交的退化网格radialSegmentsnumber12径向分段数环截面围绕管中心的小圆周上的分段数量tubularSegmentsnumber48管向分段数环绕主圆一周方向上的分段数量arcnumberMath.PI * 2中心角弧度决定环体沿主圆环绕的完整程度小于2π时生成“弧段/缺口环”thetaStartnumber0管向扫描起始角弧度thetaLengthnumberMath.PI * 2管向扫描长度弧度官方文档给出的最小使用示例黄色甜甜圈如下const geometry new THREE.TorusGeometry( 10, 3, 16, 100 ); const material new THREE.MeshBasicMaterial( { color: 0xffff00 } ); const torus new THREE.Mesh( geometry, material ); scene.add( torus );关于默认值与合法性的两点说明源码对radialSegments与tubularSegments执行Math.floor( radialSegments )取整TorusGeometry.js#L54-L55因此传入小数分段数会被向下取整源码并未强制限制最小分段数但分段数过小如1、2会产生扁平的退化形状radialSegments取3以上才能呈现立体感的管道截面。thetaStart与thetaLength控制的是“管向扫描”沿主圆方向的起止区间与常见球体几何SphereGeometry的thetaStart/thetaLength语义一致而arc同样沿主圆方向生效。当三者组合使用时可以实现“只保留一段 90° 圆弧”的半开放环体多用于烟圈、飞环等特效造型。构造参数被完整保存于 .parameters构造函数会把七个参数原样快照存入this.parametersTorusGeometry.js#L44-L52this.parameters { radius: radius, tube: tube, radialSegments: radialSegments, tubularSegments: tubularSegments, arc: arc, thetaStart: thetaStart, thetaLength: thetaLength, };需要强调的是parameters只是构造时的参数留档修改它并不会重建或改变已生成的几何体。若希望改变形状只能重新new一个实例同时copy()方法在深拷贝几何体时也会用Object.assign( {}, source.parameters )复制参数副本避免两个实例共享同一参数对象。几何体 data 的常用参数选择在 interactive/演示类示例中一个兼顾细腻程度与性能的实用组合是new THREE.TorusGeometry( 3, 1, 16, 100 ); // 主半径 3管半径 1径向 16 段管向 100 段仓库中大量示例采用了相近取值例如后处理轮廓示例new TorusGeometry( 1, 0.3, 16, 100 )、后处理遮罩示例new TorusGeometry( 3, 1, 16, 32 )等均可在 examples 目录 中检索验证。低分段取值的实例如控件 gizmo 使用TorusGeometry( radius, 0.0075, 3, 64 )则证明该几何体可被灵活用于辅助线、编辑手柄等对网格精度要求不高但对性能敏感的场景。三、源码级解析TorusGeometry 是如何逐顶点生成的TorusGeometry 源码 的构造逻辑非常清晰可划分为四个阶段。理解这一流程有助于你根据需求预估顶点数、定位性能瓶颈。阶段一准备缓冲数组先创建四个数组分别承载索引、顶点、法线、UVconst indices []; const vertices []; const normals []; const uvs [];并用三个Vector3作为临时运算对象center记录环心、vertex记录当前顶点、normal记录当前法线避免在循环内反复分配对象。阶段二双重循环生成顶点、法线与 UV外层循环j从0到radialSegments沿管截面方向内层循环i从0到tubularSegments沿主圆方向const v thetaStart ( j / radialSegments ) * thetaLength; // 截面上圆周角 const u i / tubularSegments * arc; // 沿主圆的角度顶点坐标由参数方程直接得出vertex.x ( radius tube * Math.cos( v ) ) * Math.cos( u ); vertex.y ( radius tube * Math.cos( v ) ) * Math.sin( u ); vertex.z tube * Math.sin( v );可以看到环体位于 XY 平面展开radius tube·cos(v)决定当前点到主圆轴线的水平距离tube·sin(v)决定高度分量这与数学上标准的环面参数方程完全一致。法线采用“顶点减环心再归一化”的做法先计算该角度u下环心在 XY 平面上的投影点center再对vertex - center归一化——这样得到的法线必然指向环体外侧沿半径方向背离管道中心线保证光照结果正确。UV 坐标则按归一化比例写入uvs.push( i / tubularSegments ); // u ∈ [0,1] uvs.push( j / radialSegments ); // v ∈ [0,1]因此纹理默认沿环面完整包裹一周便于直接贴棋盘格、迷彩等平铺纹理examples/misc_uv_tests.html即用TorusGeometry( 50, 20, 8, 8 )做 UV 展开检测。阶段三生成三角形索引由于顶点按“径向在外、管向在内”的网格规律排列每个四边形面片可拆为两个三角形。源码以当前格点(i, j)推导出四个角点的线性索引a/b/c/d每格输出两个三角形indices.push( a, b, d ); indices.push( b, c, d );顶点总数与三角形面数可提前估算顶点数 ( radialSegments 1 ) × ( tubularSegments 1 )三角形数 radialSegments × tubularSegments × 2以官方示例TorusGeometry( 10, 3, 16, 100 )计算共(161)×(1001) 1717个顶点、16×100×2 3200个三角形属于极轻量级网格可以放心用于实时渲染。阶段四装配缓冲属性最后把数据写入几何体this.setIndex( indices ); this.setAttribute( position, new Float32BufferAttribute( vertices, 3 ) ); this.setAttribute( normal, new Float32BufferAttribute( normals, 3 ) ); this.setAttribute( uv, new Float32BufferAttribute( uvs, 2 ) );其中Float32BufferAttributeFloat32BufferAttribute会以每 3 个/每 2 个浮点数为一个顶点分量进行解释。装配完成后几何体即拥有完整的position / normal / uv三套属性与索引缓冲可直接交给Mesh渲染也可配合后续介绍的toJSON流程进行序列化。四、属性与实例方法.parameters : Object保存构造时使用的全部参数语义为“参数快照”。修改其中任一字段均不影响已经生成的几何体若需几何体可编辑地改变形态应改用参数对象在构造前生成新实例或直接对position/normal属性做运行时逐顶点修改并调用computeVertexNormals()。.type : String实例属性type被固定为TorusGeometryTorusGeometry.js#L35序列化/反序列化与toJSON流程依靠该字符串区分几何体类型。对应单元测试中object.type TorusGeometry断言即为此设计提供回归保护。copy( source ) : TorusGeometry继承自BufferGeometry并被重写TorusGeometry.js#L136-L144先调用父类super.copy( source )复制索引、属性、包围盒等再用Object.assign( {}, source.parameters )深拷贝一份参数从而保证两个实例互不影响。静态方法 .fromJSON( data : Object ) : TorusGeometry从 JSON 对象还原几何体的工厂方法TorusGeometry.js#L153-L157static fromJSON( data ) { return new TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc, data.thetaStart, data.thetaLength ); }它按序列化后的字段顺序逐一还原七个构造参数。在实际工程中通常配合场景序列化链路使用scene.toJSON()会把几何体连同type与各参数写入 JSON再由ObjectLoader场景加载器依据type查表调用TorusGeometry.fromJSON完成重建。因此只要你手动构造与.parameters结构一致的 JSON 数据同样可以通过该工厂方法还原实例。五、与 TorusKnotGeometry环面纽结的区分很多初学者会把两者混淆。虽然都带 “Torus” 前缀TorusKnotGeometry 源码 生成的是“绕自身扭转多次的纽结曲线管道”形状可类比麻花/绳结而非标准甜甜圈TorusGeometry截面圆心沿固定半径的圆周扫描一周是规则环面TorusKnotGeometry中心线是 (p,q) 纽结曲线顶点沿曲线建立 Frenet 型正交基源码中以T/N/B表示逐段挤出管道因此参数中还额外包含决定绕行方式的p、q如p2,q3。在几何体浏览器 geometry-browser.html 场景中两者都列于同一分组可直接对比。两者都从src/geometries/Geometries.js统一 re-export导出索引最终由 Three.js 主入口 挂载到全局命名空间因此可直接通过THREE.TorusGeometry访问。六、测试与实战验证仓库为 TorusGeometry 提供了完备的 QUnit 测试见 test/unit/src/geometries/TorusGeometry.tests.js覆盖维度包括继承关系断言实例是BufferGeometry的子类可实例化new TorusGeometry()无参构造成功type 标记type TorusGeometry标准几何体测试对 7 种参数组合从只传radius到七参全传逐一执行runStdGeometryTests校验索引/属性/包围盒等通用几何约定。该测试矩阵同时印证了“每个构造参数均可独立省略、均走默认值”的接口设计为读者调用 API 提供了行为参照。如果要在本地快速运行相关单测验证结论可执行npx qunit test/unit/three.source.unit.js其中test/unit/three.source.unit.js会把TorusGeometry.tests.js并入完整几何体测试集执行。七、完整实战示例带旋转与光照的环体网格综合上文知识一个可直接运行的完整页面级场景示例如下script typeimportmap { imports: { three: ./build/three.module.js } } /script script typemodule import * as THREE from three; import { OrbitControls } from ./examples/jsm/controls/OrbitControls.js; const scene new THREE.Scene(); const camera new THREE.PerspectiveCamera( 45, innerWidth / innerHeight, 0.1, 100 ); camera.position.set( 0, 2, 6 ); const renderer new THREE.WebGLRenderer( { antialias: true } ); renderer.setSize( innerWidth, innerHeight ); document.body.appendChild( renderer.domElement ); new OrbitControls( camera, renderer.domElement ); // 部分环体只扫 1.5π 角度形成“缺口甜甜圈” const geometry new THREE.TorusGeometry( 2, 0.8, 32, 96, Math.PI * 1.5 ); const material new THREE.MeshStandardMaterial( { color: 0x44aaff, roughness: 0.3, metalness: 0.4 } ); const torus new THREE.Mesh( geometry, material ); scene.add( torus ); scene.add( new THREE.AmbientLight( 0xffffff, 0.6 ) ); scene.add( new THREE.DirectionalLight( 0xffffff, 1.0 ).position.set( 3, 4, 5 ) ); function animate () { requestAnimationFrame( animate ); torus.rotation.x 0.005; torus.rotation.y 0.01; renderer.render( scene, camera ); } animate(); /script关键点总结设置arc Math.PI * 2可创建带缺口的弧形环控制radialSegments与tubularSegments是平衡网格细腻度与渲染开销的最直接手段环体自带正确的法线与 UV配合MeshStandardMaterial、法线贴图或平铺纹理均可直接获得正确光照若需把环体用于物理碰撞体、gizmo 手柄或后处理遮罩可参考TransformControls的TorusGeometry( radius, 0.0075, 3, 64 )、misc_exporter_gcode的TorusGeometry( 5, 2, 24, 100 )等真实用例选择较低分段数即可获得廉价而可靠的形状。参考资料仓库内部官方 API 文档源文件TorusGeometry.html.md本文主体的官方出处核心实现src/geometries/TorusGeometry.js几何体导出入口src/geometries/Geometries.js单元测试test/unit/src/geometries/TorusGeometry.tests.js可交互几何体对比场景docs/scenes/geometry-browser.html相关几何体对比TorusKnotGeometry 源码 src/geometries/TorusKnotGeometry.js【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考