You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Three.js中添加2D文本标签?已尝试Sprites、FontLoader等

在Three.js中为3D物体添加2D文本标签的实现指引

问题描述

我想在3D物体旁添加如图所示的2D文本标签,试过Sprites(新版Three.js里似乎无法使用)、FontLoader及多种渲染机制都没成功。了解到可以用CSS3D,但不清楚该从示例代码中借鉴哪些内容,附上我的关键代码片段,希望能得到方向指引。

我的关键代码

<script src="https://unpkg.com/three@0.132.2/build/three.min.js"></script>
<script src="https://unpkg.com/three@0.132.2/examples/js/loaders/GLTFLoader.js"></script>
<script src="https://unpkg.com/three@0.132.2/examples/js/loaders/DRACOLoader.js"></script>
<script src="https://unpkg.com/three@0.132.2/examples/js/controls/OrbitControls.js"></script>

<canvas id="c"></canvas>

<script>
window.addEventListener('load', init);

function init() {
    const width = window.innerWidth;
    const height = window.innerHeight;

    const canvasElement = document.querySelector('#c');
    const renderer = new THREE.WebGLRenderer({
        canvas: canvasElement,
    });
    renderer.setSize(width, height);

    const scene = new THREE.Scene();
    scene.background = new THREE.Color( 0xf5e8c6 );

    // 补充loader初始化(原代码遗漏部分)
    const loader = new THREE.GLTFLoader();
    const dracoLoader = new THREE.DRACOLoader();
    dracoLoader.setDecoderPath('js/draco/'); // 若使用DRACO压缩需设置解码器路径
    loader.setDRACOLoader(dracoLoader);

    loader.load('js/PricklyPearObject/scene.gltf', (gltf) => {
        const model = gltf.scene;
        model.scale.set( 0.1,0.1,0.1);
        model.position.set(-2, 0, 0);
        scene.add(model);
    });
}
</script>

基于CSS3D的实现步骤与修改代码

1. 引入CSS3D相关依赖

在现有脚本后添加CSS3DRenderer的引用:

<script src="https://unpkg.com/three@0.132.2/examples/js/renderers/CSS3DRenderer.js"></script>

2. 完善初始化逻辑(相机、控制器、CSS渲染器)

修改init函数,补充核心功能代码:

function init() {
    const width = window.innerWidth;
    const height = window.innerHeight;

    const canvasElement = document.querySelector('#c');
    const renderer = new THREE.WebGLRenderer({
        canvas: canvasElement,
    });
    renderer.setSize(width, height);

    // 创建相机
    const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 100);
    camera.position.set(0, 0, 5);

    // 创建轨道控制器
    const controls = new THREE.OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;

    // 创建CSS3D渲染器
    const cssRenderer = new THREE.CSS3DRenderer();
    cssRenderer.setSize(width, height);
    cssRenderer.domElement.style.position = 'absolute';
    cssRenderer.domElement.style.top = '0';
    cssRenderer.domElement.style.pointerEvents = 'none'; // 不遮挡WebGL画布交互
    document.body.appendChild(cssRenderer.domElement);

    const scene = new THREE.Scene();
    scene.background = new THREE.Color( 0xf5e8c6 );

    const loader = new THREE.GLTFLoader();
    const dracoLoader = new THREE.DRACOLoader();
    dracoLoader.setDecoderPath('js/draco/');
    loader.setDRACOLoader(dracoLoader);

    loader.load('js/PricklyPearObject/scene.gltf', (gltf) => {
        const model = gltf.scene;
        model.scale.set( 0.1,0.1,0.1);
        model.position.set(-2, 0, 0);
        scene.add(model);

        // 创建并添加文本标签
        const labelDiv = document.createElement('div');
        labelDiv.style.padding = '4px 8px';
        labelDiv.style.background = 'rgba(255,255,255,0.9)';
        labelDiv.style.borderRadius = '4px';
        labelDiv.style.fontSize = '14px';
        labelDiv.style.whiteSpace = 'nowrap';
        labelDiv.textContent = '仙人掌';

        // 将HTML元素包装为CSS3DObject
        const labelObject = new THREE.CSS3DObject(labelDiv);
        // 定位到模型上方偏右位置(数值根据模型缩放调整)
        labelObject.position.copy(model.position);
        labelObject.position.y += 1;
        labelObject.position.x += 0.5;
        // 让标签始终面向相机
        labelObject.lookAt(camera.position);

        scene.add(labelObject);
    });

    // 渲染循环:同时渲染WebGL和CSS3D场景
    function animate() {
        requestAnimationFrame(animate);
        controls.update();
        renderer.render(scene, camera);
        cssRenderer.render(scene, camera);
        // 如需标签持续跟随相机视角,可在此处更新朝向
        // const label = scene.getObjectByName('自定义标签名称');
        // if(label) label.lookAt(camera.position);
    }
    animate();
}

核心要点说明

  • CSS3D的本质是将HTML元素转换为Three.js可识别的对象,能和3D模型一起参与场景的位置、旋转变换
  • CSS3DRenderer的DOM元素必须设置绝对定位,叠加在WebGL画布之上,关闭pointerEvents避免遮挡画布交互
  • 标签位置需根据模型实际缩放比例调整,确保显示在模型旁合适位置
  • 若需标签始终跟随相机视角,可在渲染循环中调用labelObject.lookAt(camera.position)更新朝向

内容的提问来源于stack exchange,提问作者Ro Ba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 09:15:59