如何在基于Three.js R71的Forge Viewer中添加TextGeometry?
在Forge Viewer中使用Three.js生成自动文本的可行方案与踩坑解决
完全可以在Forge Viewer中实现自动生成文本的需求,不过因为Viewer内置的是Three.js R71这个旧版本,确实需要适配它的API和资源要求,我帮你梳理几个可行的方案,以及你遇到的问题的解决办法:
方案一:直接使用Three.js R71的TextGeometry
这是最贴合3D文本需求的方案,核心要解决字体加载的兼容性问题:
1. 准备对应版本的字体文件
R71的TextGeometry依赖的字体JSON格式和新版Three.js不兼容,你必须使用R71官方提供的字体文件(比如helvetiker_regular.typeface.json),可以从Three.js R71源码包的examples/fonts目录里获取,把它放到你的项目静态资源目录中。
2. 正确加载字体并创建文本
R71的字体加载和文本创建写法和新版有差异,参考下面的代码:
// 假设你已经初始化好了Viewer实例,这里用NOP_VIEWER指代 const viewer = NOP_VIEWER; // 加载R71版本的字体 const fontLoader = new THREE.FontLoader(); fontLoader.load('/path/to/helvetiker_regular.typeface.json', (font) => { // 创建TextGeometry const textGeo = new THREE.TextGeometry('自动生成的文本', { font: font, size: 8, height: 1.5, curveSegments: 12, // 控制文本平滑度 bevelEnabled: false }); // 让文本居中(可选) textGeo.computeBoundingBox(); const centerX = -0.5 * (textGeo.boundingBox.max.x - textGeo.boundingBox.min.x); textGeo.translate(centerX, 0, 0); // 创建材质与网格 const textMat = new THREE.MeshPhongMaterial({ color: 0xff5500 }); const textMesh = new THREE.Mesh(textGeo, textMat); // 设置文本位置(这里示例放在场景原点上方) textMesh.position.set(0, 15, 0); // 添加到Viewer场景并刷新渲染 viewer.impl.scene.add(textMesh); viewer.impl.invalidate(true); });
你遇到的「字体不存在」错误的原因
- 大概率是用了新版Three.js的字体文件,格式不兼容;
- 字体文件路径错误,要确保资源能被正确访问(本地测试要开服务器,避免跨域问题)。
方案二:Canvas转纹理的3D文本(更省心的替代方案)
如果不想纠结旧版本字体的问题,可以先在Canvas上绘制2D文本,再转换成Three.js纹理贴在平面上,兼容性更好:
const viewer = NOP_VIEWER; // 创建Canvas并绘制文本 const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = 300; canvas.height = 80; ctx.fillStyle = '#ffffff'; ctx.font = '50px sans-serif'; ctx.textAlign = 'center'; ctx.fillText('自动生成文本', canvas.width / 2, canvas.height / 2 + 15); // 转成Three.js纹理 const texture = new THREE.Texture(canvas); texture.needsUpdate = true; // 创建带纹理的平面 const planeGeo = new THREE.PlaneGeometry(20, 5); const planeMat = new THREE.MeshBasicMaterial({ map: texture, transparent: true }); const textPlane = new THREE.Mesh(planeGeo, planeMat); // 设置位置并添加到场景 textPlane.position.set(0, 10, 0); viewer.impl.scene.add(textPlane); viewer.impl.invalidate(true);
解决上层叠加Canvas的布局问题
如果你坚持用Viewer上层的独立Canvas,需要解决坐标映射和尺寸同步的问题:
- 同步Canvas尺寸:监听Viewer的窗口 resize 事件,让Canvas大小和Viewer容器一致:
const overlayCanvas = document.getElementById('text-overlay'); function syncCanvasSize() { overlayCanvas.width = viewer.container.clientWidth; overlayCanvas.height = viewer.container.clientHeight; } // 初始化和窗口变化时同步 syncCanvasSize(); viewer.addEventListener(Autodesk.Viewing.VIEWER_RESIZED_EVENT, syncCanvasSize);
- 正确映射3D坐标到2D:用Viewer的
worldToClient方法把模型中的3D点转换成屏幕坐标,再定位Canvas上的文本:
// 示例:获取模型中某个3D点的屏幕位置 const worldPoint = new THREE.Vector3(10, 5, 0); const screenPoint = viewer.worldToClient(worldPoint); // 在Canvas上绘制文本到对应位置 const ctx = overlayCanvas.getContext('2d'); ctx.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height); ctx.fillStyle = '#ff0000'; ctx.font = '24px sans-serif'; ctx.fillText('标记文本', screenPoint.x, screenPoint.y);
以上几种方案都能实现「JavaScript自动生成文本,无需用户操作」的需求,你可以根据自己的场景选择最合适的。
内容的提问来源于stack exchange,提问作者Sam Curry
相关产品推荐
相关产品推荐

