背景
原创内容
Three.js标签显示指南
Threejs
前端开发
2025-05-30
11分钟
92
头像
Dean
Threejs

在 Three.js 项目中,为模型特定位置添加标签显示信息(如位置介绍)有几种常见方法,以下是详细的实现方案:

1. HTML/CSS 叠加标签(DOM 元素)

原理:将 HTML 元素(如 <div>)绝对定位在模型对应位置,通过坐标转换实现跟随。

javascript 复制代码
// 创建 HTML 标签
const label = document.createElement('div');
label.className = 'label';
label.textContent = '标签内容';
document.body.appendChild(label);

// 在动画循环中更新位置
function animate() {
  const vector = model.position.clone(); // 模型局部坐标
  vector.project(camera); // 转换为屏幕坐标

  label.style.left = `${(vector.x * 0.5 + 0.5) * 100}%`;
  label.style.top = `${(-vector.y * 0.5 + 0.5) * 100}%`;
}

优点:简单快捷,支持复杂 CSS 样式。
缺点:性能较差(频繁 DOM 操作),难以处理遮挡。

2. CSS2DRenderer / CSS3DRenderer

原理:使用 Three.js 官方扩展将 HTML 元素集成到 3D 场景中。

javascript 复制代码
import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';

// 创建标签元素
const labelDiv = document.createElement('div');
labelDiv.textContent = '标签内容';
const label = new CSS2DObject(labelDiv);

// 将标签添加到模型特定位置
model.add(label);
label.position.set(0, 1, 0); // 相对于模型的局部坐标

// 初始化渲染器
const labelRenderer = new CSS2DRenderer();
labelRenderer.domElement.style.position = 'absolute';
document.body.appendChild(labelRenderer.domElement);

// 在渲染循环中更新
function render() {
  labelRenderer.render(scene, camera);
}

优点:自动处理遮挡和坐标转换,性能优于纯 DOM。
缺点:需要额外管理渲染器,CSS3D 变换可能受限。
注意点:
CSS3DRenderer 本质上是将 HTML 元素通过 CSS 3D 变换放置在场景中,这些元素并不真正参与 WebGL 的 3D 渲染管线。它们实际上是漂浮在 WebGL 画布上方的 2D DOM 元素,只是通过坐标映射模拟了 3D 位置。
因此:
CSS3D 元素无法被 WebGL 渲染的 3D 模型遮挡(始终显示在最上层或最下层)。

3. Sprite 文本标签

原理:使用 Sprite 和 Canvas 生成动态纹理,创建始终面向相机的 2D 标签。

javascript 复制代码
// 创建 Canvas 纹理
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'white';
ctx.font = '24px Arial';
ctx.fillText('标签内容', 10, 50);

const texture = new THREE.CanvasTexture(canvas);
const material = new THREE.SpriteMaterial({ map: texture });
const sprite = new THREE.Sprite(material);

// 设置标签位置和缩放
sprite.position.set(0, 1, 0); // 模型局部坐标
sprite.scale.set(1, 0.5, 1); // 根据内容调整
model.add(sprite);

优点:完全集成在 WebGL 上下文中,性能较好。
缺点:动态更新文本需重新生成纹理,不支持复杂 HTML 内容。

4. TextGeometry 3D 文本

原理:使用 TextGeometry 生成三维文字模型。

javascript 复制代码
import { FontLoader } from 'three/addons/loaders/FontLoader.js';
import { TextGeometry } from 'three/addons/geometries/TextGeometry.js';

// 加载字体
const loader = new FontLoader();
loader.load('fonts/helvetiker_regular.typeface.json', (font) => {
  const textGeo = new TextGeometry('标签内容', {
    font: font,
    size: 0.5,
    height: 0.1,
  });

  const textMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff });
  const textMesh = new THREE.Mesh(textGeo, textMaterial);
  
  // 将文本添加到模型位置
  model.add(textMesh);
  textMesh.position.set(0, 1, 0);
});

优点:真正的 3D 文本,可进行物理交互。
缺点:依赖字体文件,文本锯齿问题,不适合长文本。

5. 自定义 Shader 标签

原理:通过着色器实现动态标签效果(如始终面向相机、描边等)。

glsl 复制代码
// 顶点着色器中添加 Billboard 效果
void main() {
  vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
  gl_Position = projectionMatrix * mvPosition;
}

优点:高度定制化,性能最佳。
缺点:需要 GLSL 知识,开发成本高。

选择建议

  • 简单场景:使用 CSS2DRenderer(平衡易用性和性能)。
  • 大量动态标签:选择 Sprite 或自定义 Shader。
  • 需要 3D 效果:使用 TextGeometry
  • 复杂交互需求:优先考虑 HTML/CSS 方案。