
在 Three.js 项目中,为模型特定位置添加标签显示信息(如位置介绍)有几种常见方法,以下是详细的实现方案:
原理:将 HTML 元素(如 <div>)绝对定位在模型对应位置,通过坐标转换实现跟随。
// 创建 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 操作),难以处理遮挡。
原理:使用 Three.js 官方扩展将 HTML 元素集成到 3D 场景中。
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 模型遮挡(始终显示在最上层或最下层)。
原理:使用 Sprite 和 Canvas 生成动态纹理,创建始终面向相机的 2D 标签。
// 创建 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 内容。
原理:使用 TextGeometry 生成三维文字模型。
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 文本,可进行物理交互。
缺点:依赖字体文件,文本锯齿问题,不适合长文本。
原理:通过着色器实现动态标签效果(如始终面向相机、描边等)。
// 顶点着色器中添加 Billboard 效果
void main() {
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * mvPosition;
}
优点:高度定制化,性能最佳。
缺点:需要 GLSL 知识,开发成本高。
CSS2DRenderer(平衡易用性和性能)。Sprite 或自定义 Shader。TextGeometry。