Three.js教程:如何在r.64+版本中定位文本精灵?
嘿,我来帮你搞定这个问题!Three.js r64+版本在Sprite的处理上确实有一些小变化,咱们一步步调整旧代码,实现Box边缘的边长标注。
适配r64+的文本精灵创建函数
首先更新旧版的makeTextSprite函数,适配新版本的API:
function makeTextSprite(message, opts) { const parameters = opts || {}; const fontface = parameters.fontface || 'Arial'; const fontsize = parameters.fontsize || 32; const textColor = parameters.textColor || '#ffffff'; const bgColor = parameters.bgColor || 'rgba(0,0,0,0.5)'; // 创建画布并设置上下文 const canvas = document.createElement('canvas'); let context = canvas.getContext('2d'); // 先设置字体,计算文本尺寸 context.font = `${fontsize}px ${fontface}`; const metrics = context.measureText(message); const textWidth = metrics.width; const textHeight = fontsize * 1.2; // 预留行高,避免文字被截断 // 调整画布尺寸,给文本加边距提升可读性 canvas.width = textWidth + 20; canvas.height = textHeight + 10; // 画布尺寸变更后重新获取上下文 context = canvas.getContext('2d'); context.font = `${fontsize}px ${fontface}`; // 绘制半透明背景(可选,让文本在复杂场景中更清晰) context.fillStyle = bgColor; context.fillRect(0, 0, canvas.width, canvas.height); // 绘制文本,居中对齐 context.fillStyle = textColor; context.textBaseline = 'middle'; context.textAlign = 'center'; context.fillText(message, canvas.width / 2, canvas.height / 2); // 创建纹理并标记需要更新 const texture = new THREE.Texture(canvas); texture.needsUpdate = true; // 这一步很关键,否则纹理不会生效 // 创建精灵材质 const spriteMaterial = new THREE.SpriteMaterial({ map: texture, transparent: true, depthTest: false, // 可选:关闭深度测试,让文本始终显示在最上层 }); // 创建精灵并调整缩放 const sprite = new THREE.Sprite(spriteMaterial); const scaleFactor = 0.1; // 根据场景整体缩放调整这个值 sprite.scale.set(textWidth * scaleFactor, textHeight * scaleFactor, 1); return sprite; }
定位文本精灵到Box边缘中点
接下来的核心是计算Box每个边缘的中点坐标,把精灵放在对应位置。假设你已经创建了Box网格:
// 创建示例Box(尺寸:x=2,y=1,z=3) const boxGeometry = new THREE.BoxGeometry(2, 1, 3); const boxMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true }); const boxMesh = new THREE.Mesh(boxGeometry, boxMaterial); scene.add(boxMesh);
手动定位关键边缘
你可以手动计算边缘中点,比如:
// 标注x方向边长(正面底部边缘,中点(0, -0.5, 1.5)) const xLengthSprite = makeTextSprite('2', { fontsize: 24, textColor: '#ff0000' }); xLengthSprite.position.set(0, -0.5, 1.51); // z轴微移,避免和Box表面重合 scene.add(xLengthSprite); // 标注y方向边长(右侧垂直边缘,中点(1, 0, 1.5)) const yLengthSprite = makeTextSprite('1', { fontsize: 24, textColor: '#00ff00' }); yLengthSprite.position.set(1.01, 0, 1.5); // x轴微移 scene.add(yLengthSprite); // 标注z方向边长(顶部深度边缘,中点(1, 0.5, 0)) const zLengthSprite = makeTextSprite('3', { fontsize: 24, textColor: '#0000ff' }); zLengthSprite.position.set(1, 0.51, 0); // y轴微移 scene.add(zLengthSprite);
自动遍历所有边缘标注
如果要给Box的所有边缘自动标注,可以利用computeEdges()方法获取所有边缘,批量计算中点:
// 先计算Box的所有边缘 boxGeometry.computeEdges(); // 遍历每个边缘,创建文本精灵 boxGeometry.edges.forEach(edge => { // 获取边缘的两个顶点 const v1 = boxGeometry.vertices[edge[0]]; const v2 = boxGeometry.vertices[edge[1]]; // 计算边缘中点坐标 const midPoint = new THREE.Vector3( (v1.x + v2.x) / 2, (v1.y + v2.y) / 2, (v1.z + v2.z) / 2 ); // 计算边长并格式化 const length = v1.distanceTo(v2).toFixed(1); // 创建文本精灵并定位 const sprite = makeTextSprite(length, { fontsize: 20 }); sprite.position.copy(midPoint); // 微移精灵,避免和Box线框重合 const offset = midPoint.clone().normalize().multiplyScalar(0.05); sprite.position.add(offset); scene.add(sprite); });
重要注意事项
- 精灵缩放调整:
scaleFactor的值需要根据你的场景整体缩放比例来调整,确保文本大小适配场景。 - 遮挡问题:如果文本被Box遮挡,可以开启
depthTest: false让精灵始终显示在最前面,或者微调position的偏移量。 - 动态文本更新:如果需要修改精灵的文本内容,更新canvas后一定要设置
texture.needsUpdate = true,否则纹理不会刷新。
内容的提问来源于stack exchange,提问作者Alex Lenail
相关产品推荐
相关产品推荐

