多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

three.js RingGeometry 环形几何体完全指南:构造参数、UV/法线原理与工程实践

three.js RingGeometry 环形几何体完全指南:构造参数、UV/法线原理与工程实践 three.js RingGeometry 环形几何体完全指南构造参数、UV/法线原理与工程实践【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js导读RingGeometry是 three.js 内置的二维环形圆环面片几何体生成类位于几何体模块 src/geometries/RingGeometry.js常被用于制作甜甜圈形贴片、仪表盘刻度底环、靶环、放射状界面元素以及任何需要带内孔圆盘外形的平面网格。读完本文你将掌握其全部六个构造参数的含义与默认值、源码级别的顶点/索引/UV/法线生成原理以及如何通过thetaStart/thetaLength切出扇环并结合材质与序列化 API 在真实工程中正确使用它。类定位与继承关系RingGeometry生成的是位于 XY 平面、以原点为中心、沿 Z 轴法线方向的二维环形几何体其厚度为 0。类文档给出的继承链为EventDispatcher → BufferGeometry → RingGeometry在源码中它直接继承自BufferGeometrysrc/core/BufferGeometry.js而事件分发能力来自BufferGeometry内部的EventDispatcher混入。单元测试 test/unit/src/geometries/RingGeometry.tests.js 也专门断言了这一点RingGeometry extends from BufferGeometry并验证默认构造、各参数逐级传入构造以及几何体通用测试均可通过。基础用法三步建出一个环官方文档给出的最小可运行示例即是一个双面可见、内半径 1、外半径 5、32 段的黄色环const geometry new THREE.RingGeometry( 1, 5, 32 ); const material new THREE.MeshBasicMaterial( { color: 0xffff00, side: THREE.DoubleSide } ); const mesh new THREE.Mesh( geometry, material ); scene.add( mesh );需要特别说明side: THREE.DoubleSideRingGeometry的每个三角面都只有 Z 方向的法线法线固定为( 0, 0, 1 )即只有正面可见。默认相机沿 Z 朝原点观察时能直接看到正面一旦旋转网格或从背面观察背面会被剔除因此官方示例与多数演示都显式开启双面材质避免环消失的困惑。构造参数全景构造函数签名与文档一致默认值同时体现在 RingGeometry.js 的参数默认值中new THREE.RingGeometry( innerRadius, // 内半径 outerRadius, // 外半径 thetaSegments, // 圆周切向分段数 phiSegments, // 半径方向径向分段数 thetaStart, // 起始角弧度 thetaLength // 圆心角跨度弧度 )六个参数逐一说明如下参数默认值最小值源码钳制含义与要点innerRadius0.5无可为任意非负数环的内孔半径必须小于outerRadius否则几何异常。outerRadius1无环的外缘半径。thetaSegments323小于 3 会被钳到 3沿圆周切向的分段数数值越大圆越圆滑。phiSegments11小于 1 会被钳到 1内半径到外半径之间径向的分段数越大则径向网格越细密。thetaStart0无起始角度弧度制0 对应 X 方向按逆时针展开。thetaLengthMath.PI * 2无覆盖的圆心角弧度2π为完整圆环小于2π即切出扇环。关于最小值的钳制在源码中有明确实现thetaSegments Math.max( 3, thetaSegments ); phiSegments Math.max( 1, phiSegments );也就是说即使传入thetaSegments: 1实际也会按 3 段生成——这保证了环形拓扑至少有一个可渲染的封闭轮廓。源码级原理顶点布局、索引、UV 与法线RingGeometry并非复杂的建模类其核心逻辑完全在构造器内以两层循环完成。理解其网格排布有助于预判细分密度与 UV 走向。网格是一个径向 × 切向的格网顶点按由内向外逐圈生成共( phiSegments 1 ) × ( thetaSegments 1 )个顶点外层循环j表示径向行0 到phiSegments内层循环i表示切向列0 到thetaSegments。半径与角度的递推径向每行进一次当前半径从innerRadius开始按固定步长递增let radius innerRadius; const radiusStep ( outerRadius - innerRadius ) / phiSegments; ... // 每行结束 radius radiusStep;切向位置则由当前行半径与角度共同决定角度在[ thetaStart, thetaStart thetaLength ]上均匀采样const segment thetaStart i / thetaSegments * thetaLength; vertex.x radius * Math.cos( segment ); vertex.y radius * Math.sin( segment );也就是说每个顶点的位置本质是极坐标( radius, segment )向笛卡尔坐标的转换且z恒为 0。可以由此推断增加thetaSegments让轮廓更接近正圆文档所称more round即指此增加phiSegments则让径向有更多细分配合顶点颜色、位移等逐顶点效果或扇形渐变贴图才有意义。法线与 UV每个顶点都写入统一的 Z 法线normals.push( 0, 0, 1 );UV 按外半径归一化到[0, 1]范围uv.x ( vertex.x / outerRadius 1 ) / 2; uv.y ( vertex.y / outerRadius 1 ) / 2;由于顶点坐标的最大模长就是outerRadius该映射始终落在[0,1]内外圈 UV 会贴近单位方块的圆周最大值约 1内孔边缘则收敛到由innerRadius/outerRadius决定的内部圆。因此若给环贴一张纹理纹理中心对应的环面外方形区域无法被采样到——UV 只会覆盖以原点为中心的、半径比约等于内外半径比的那一环形带而非整张纹理。索引与三角形绕序每个四边形单元拆成两个三角形角点按a,b,d与b,c,d两组索引入堆indices.push( a, b, d ); indices.push( b, c, d );最后统一写入索引缓冲与三个顶点属性缓冲this.setIndex( indices ); this.setAttribute( position, new Float32BufferAttribute( vertices, 3 ) ); this.setAttribute( normal, new Float32BufferAttribute( normals, 3 ) ); this.setAttribute( uv, new Float32BufferAttribute( uvs, 2 ) );从三角形索引绕序可以推断面朝 Z、正面可见正面面向 Z 方向的观察者这也印证了前面需要DoubleSide的建议。常用实战形态半环 / 扇环进度环、仪表弧完整圆环是默认形态把thetaStart与thetaLength配合使用即可切出任意角度跨度的扇环例如270° 开口环const gauge new THREE.RingGeometry( 6, 7, 64, 1, 0, Math.PI * 1.5 );薄边厚边环与径向渐变细分想让环的径向边缘更精细例如顶点色从内到外渐变就提高phiSegments。仓库演示场景 docs/scenes/geometry-browser.html 就提供了一个带 GUI 的实时调节器其RingGeometry面板把六个参数全部暴露出来其中innerRadius/outerRadius可在[1, 30]调节、thetaSegments/phiSegments以步长 1 在[1, 30]调节、thetaStart/thetaLength在[0, 2π]之间调节修改任一参数都会调用generateGeometry()重建几何体——这是体验各参数观感的推荐入口对应源码第 458–490 行。在合成场景中与其它几何体混排官方示例 examples/webgl_geometries.html 的几何体陈列场景中以如下方式生成了一个参数组合丰富的环object new THREE.Mesh( new THREE.RingGeometry( 10, 50, 20, 5, 0, Math.PI * 2 ), material ); object.position.set( 300, 0, 100 ); scene.add( object );即内半径 10、外半径 50、20 个切向段、5 个径向段、完整圆周的环与圆盘CircleGeometry、圆环体TorusGeometry等陈列在同一场景中便于直观对比外形差异。属性与序列化.parameters : Object构造器会把全部入参原样存入parameters供查询或序列化使用this.parameters { innerRadius: innerRadius, outerRadius: outerRadius, thetaSegments: thetaSegments, phiSegments: phiSegments, thetaStart: thetaStart, thetaLength: thetaLength };需要注意文档明确指出的语义实例化之后修改parameters不会改变已生成的几何体——它是构造快照不是实时开关。若需调整形态应重新new RingGeometry(...)并替换网格的.geometry。此外RingGeometry覆写了继承自BufferGeometry的.copy()方法用浅拷贝Object.assign( {}, source.parameters )同步parameters保证拷贝副本与源几何的参数记录一致见 RingGeometry.js。.fromJSON( data : Object ) : RingGeometry静态工厂方法把序列化的 JSON 对象还原为新的RingGeometry实例。其实现直接按 JSON 中的六个字段逐项重建static fromJSON( data ) { return new RingGeometry( data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength ); }JSON 数据的来源通常是几何体自带的toJSON()由BufferGeometry提供会把type与parameters一并导出。反序列化时引擎根据type: RingGeometry定位到本类再调用.fromJSON()完成还原。这一toJSON导出 fromJSON重建的对称模式与其它内置几何体保持一致是 GLTF 之外的轻量级几何体存档/恢复路径。回归测试与工程佐证仓库单元测试 test/unit/src/geometries/RingGeometry.tests.js 围绕该类做了三类验证继承测试断言实例是BufferGeometry的子类实例化测试默认构造即全参数缺省可正常创建对象标准几何体测试将 7 组逐级填充参数的实例从空构造到六参全传其中一组使用innerRadius: 10, outerRadius: 60, thetaSegments: 12, phiSegments: 14, thetaStart: 0.1, thetaLength: 2.0的非整数起始角/非整圆配置送入runStdGeometryTests统一校验索引、position/normal/uv 属性等 BufferGeometry 约定。这从工程层面确认了参数可以缺省、可以按任意位置逐级传入包括thetaStart/thetaLength取任意浮点弧度值的部分圆弧场景。需要留意的是由于文档示例场景与单元测试中的参数都在非零值域内实际项目中应避免innerRadius大于等于outerRadius这类破坏拓扑的输入。总结RingGeometry用三个顶点属性position、normal、uv加一份三角形索引把内外半径 切向/径向分段 起止角的极坐标参数翻译成一张平面网格。想要圆润的完整环就调大thetaSegments想要径向细节就调大phiSegments想要开口弧段就设置thetaStart与thetaLength。将其与side: THREE.DoubleSide的材质组合、通过.parameters记录参数、以.fromJSON()完成还原即可在绝大多数 2.5D 环形 UI 与几何演示场景中稳定复用。更详细的内容可继续阅读官方 API 文档 docs/pages/RingGeometry.html.md 与演示 docs/scenes/geometry-browser.html。【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表