Skip to content

十五、场景标注标签信息

更新: 12/19/2025字数: 0 字阅读: 0 分钟

CSS2DRenderer(HTML标签)

通过CSS2DRenderer.js扩展库可以把HTML元素作为标签标注三维场景。

  1. HTML元素创建标签
  2. 通过CSS2模型对象CSS2DObject,把一个HTML元素转化为一个类似threejs网格模型的对象
  3. 引入CSS2渲染器CSS2DRenderer
    1. 通过CSS2Renderer.render()渲染HTML标签
    2. CSS2Renderer.setSize()
    3. 渲染结果CSS2Renderer.domElement
  4. CSS2Renderer.domElement重新定位 threejs执行css2Renderer.render()之后,打开浏览器控制台元素选项,可以发现<div id="tag"></div>外面多了一层div父元素,CSS2Renderer.domElement对应的就是<div id="tag"></div>外面的父元素。 CSS2Renderer.domElement重新定位,叠加到canvas画布上,与canvas画布重合即可
  5. 解决HTML标签遮挡Canvas画布事件 HTML元素标签<div id="tag"></div>外面div父元素遮挡了Canvas画布鼠标事件,会造成相机控件OrbitControls的旋转、缩放等操作无效 1、设置.style.pointerEvents = none 2、设置z-index顺序
javascript
renderer.domElement.style.zIndex = -1;
css2Renderer.domElement.style.zIndex = 1;

设置CSS2模型对象CSS2DObject代码

javascript
// 引入CSS2模型对象CSS2DObject
import { CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';

const div = document.getElementById('tag');
// HTML元素转化为threejs的CSS2模型对象
const tag = new CSS2DObject(div);

// 设置标签位置
tag.position.set(50,0,50);
scene.add(tag);

设置CSS2渲染器CSS2DRenderer代码

javascript
// 引入CSS2渲染器CSS2DRenderer
import { CSS2DRenderer } from 'three/addons/renderers/CSS2DRenderer.js';

// 创建一个CSS2渲染器CSS2DRenderer
const css2Renderer = new CSS2DRenderer();
css2Renderer.setSize(width, height);
document.body.appendChild(css2Renderer.domElement);

// HTML标签<div id="tag"></div>外面父元素叠加到canvas画布上且重合
// 注意canvas网布布局方式不同,CSS相关代码写法也可能不同,不过你只要能让标签父元素叠加到canvas画布上上面且重合就行
css2Renderer.domElement.style.position = 'absolute';
css2Renderer.domElement.style.top = '0px';
//设置.pointerEvents=none,解决HTML元素标签对threejs canvas画布鼠标事件的遮挡
css2Renderer.domElement.style.pointerEvents = 'none';


// 渲染循环
function render() {
    css2Renderer.render(scene, camera);
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}
render();

css2Renderer.render()渲染本质:css2Renderer.render()渲染HTML元素对应的CSS2模型对象,本质上就是根据CSS2模型对象的xyz世界坐标,计算HTML标签元素在canvas画布上的屏幕像素坐标位置。

标签位置的不同设置方式

如果需要的mesh有多个父对象,且都有自己的位置属性.position,设置mesh标签对象位置CSS2DObject.position的时候,就需要考虑mesh父对象的位置对mesh的影响。

.getWorldPosition()方法计算世界坐标

通过.getWorldPosition()方法可以获取一个模型的世界坐标。

javascript
mesh.position.set(50,0,50);
// mesh设置一个父对象meshGroup
const meshGroup = new THREE.Group();
meshGroup.add(mesh);
// mesh位置受到父对象局部坐标.positionn影响
meshGroup.position.x = -100;

const tag = new CSS2DObject(div);
const worldPosition = new THREE.Vector3();
// 获取mesh的世界坐标(meshGroup.position和mesh.position累加结果)
mesh.getWorldPosition(worldPosition);
// mesh世界坐标复制给tag
tag.position.copy(worldPosition);

const group = new THREE.Group();
// 最后meshGroup和tag放在同一个父对象中即可
group.add(meshGroup,tag);

CSS2模型对象作为Mesh子对象

无论mesh有多少个父对象,CSS2模型对象作为Mesh子对象,可以直接继承mesh的世界坐标,相比通过.getWorldPosition()方法获取世界坐标,再设置标签模型位置CSS2DObject.position更方便。

javascript
// HTML元素转化为threejs的CSS2模型对象
const tag = new CSS2DObject(div);
//标签tag作为mesh子对象,默认受到父对象位置影响
mesh.add(tag);

标注模型几何体的某个顶点

标签模型对象作为需要标注mesh的子对象,然后获取mesh几何体某个顶点的坐标,作为标签模型对象局部坐标.position

javascript
// HTML元素转化为threejs的CSS2模型对象
const tag = new CSS2DObject(div);
//标签tag作为mesh子对象,默认受到父对象位置影响
mesh.add(tag);

const pos = geometry.attributes.position;
// 获取几何体顶点1的xyz坐标,设置标签局部坐标.position属性
tag.position.set(pos.getX(0),pos.getY(0),pos.getZ(0));

标签位置(标注工厂模型)

CSS2模型对象标注工厂设备

标签tag作为obj子对象,默认标注在工厂设备obj的局部坐标系坐标原点

javascript
loader.load("../工厂.glb", function (gltf) {
    const tag = new CSS2DObject(div);
    // const obj = gltf.scene.getObjectByName('设备A');
    const obj = gltf.scene.getObjectByName('设备B');
    //标签tag作为obj子对象,默认标注在工厂设备obj的局部坐标系坐标原点
    obj.add(tag);
})

建模软件创建空对象(控制标签位置)

除了上面调整局部坐标系方式,还有一种更灵活,更方便的标注方式,就是在你的三维建模软件中,任何你想标注的位置,创建一个空对象(空的模型对象,没有任何模型顶点数据,只是一个空对象)。

javascript
loader.load("../工厂.glb", function (gltf) {
    const tag = new CSS2DObject(div);
    // obj是建模软件中创建的一个空对象
    const obj = gltf.scene.getObjectByName('设备B标注');
    // const obj = gltf.scene.getObjectByName('停车场标注');
    //tag会标注在空对象obj对应的位置
    obj.add(tag);
})

HTML标签渲染前隐藏

在CSS2渲染器渲染HTML标签,重新定位标签之前,threejs执行代码和加载gltf模型也是需要时间的,这时候标签对应的HTML、CSS代码会显示在web页上面。

可以先把标签隐藏display: none;,等gltf模型加载完成,HTML元素转化CSS2模型对象以后,再取消HTML隐藏状态,CSS2渲染器默认会把标签设置为display: block;,这样就不用自己代码恢复HTML标签元素的隐藏状态了

javascript
<!-- CSS2渲染器渲染器之前,隐藏标签 -->
<div id="tag" style="display: none;"></div>

CSS3DRenderer渲染HTML标签

CSS3渲染器CSS3DRenderer和CSS2渲染器CSS2DRenderer整体使用流程基本相同,只是在HTML标签渲染效果方面不同,比如CSS3渲染的标签会跟着场景相机同步缩放,而CSS2渲染的标签默认保持自身像素值。

CSS2DRenderer渲染HTML元素标签,默认情况下,HTML元素会保持本身尺寸的像素值,除非你通过代码缩放。

设置CSS3渲染器代码

和CSS2渲染器代码一样设置,只需要把CSS2换成CSS3即可。

javascript
// 引入CSS3渲染器CSS3DRenderer
import {CSS3DRenderer} from 'three/addons/renderers/CSS3DRenderer.js';

// 创建一个CSS3渲染器CSS3DRenderer
const css3Renderer = new CSS3DRenderer();
css3Renderer.setSize(width, height);
// HTML标签<div id="tag"></div>外面父元素叠加到canvas画布上且重合
css3Renderer.domElement.style.position = 'absolute';
css3Renderer.domElement.style.top = '0px';
//设置.pointerEvents=none,解决HTML元素标签对threejs canvas画布鼠标事件的遮挡
css3Renderer.domElement.style.pointerEvents = 'none';
document.body.appendChild(css3Renderer.domElement);

// 渲染循环
function render() {
    css3Renderer.render(scene, camera);
    // ...
    requestAnimationFrame(render);
}

window.onresize = function () {
    ...
    // HTML标签css3Renderer.domElement尺寸重新设置
    css3Renderer.setSize(width,height);
};

设置CSS3对象模型CSS3DObject代码

也和CSS2对象模型一样

javascript
// 引入CSS3模型对象CSS3DObject
import { CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js';

const div = document.getElementById('tag');
// HTML元素转化为threejs的CSS3模型对象
const tag = new CSS3DObject(div);
//标签tag作为mesh子对象,默认标注在模型局部坐标系坐标原点
mesh.add(tag);
// 相对父对象局部坐标原点偏移80,刚好标注在圆锥
tag.position.y += 80;

禁止CSS3DObject标签对应HTMl元素背面显示

javascript
<div id="tag" style="backface-visibility: hidden;">标签内容</div>

CSS3精灵模型CSS3DSprite

CSS3精灵模型CSS3DSprite对应的HTML标签,可以跟着场景缩放,位置可以跟着场景旋转,但是自身的姿态角度始终平行于canvas画布,不受旋转影响,就像精灵模型一样Sprite

CSS3精灵模型CSS3DSprite尺寸、位置、缩放等渲染规律和CSS3对象模型CSS3DObject基本一致。

javascript
// 引入CSS3精灵模型对象CSS3DSprite
import { CSS3DSprite } from 'three/addons/renderers/CSS3DRenderer.js';

const div = document.getElementById('tag');
// HTML元素转化为threejs的CSS3精灵模型`CSS3DSprite`
const tag = new CSS3DSprite(div);
//标签tag作为mesh子对象,默认标注在模型局部坐标系坐标原点
mesh.add(tag);
// 相对父对象局部坐标原点偏移80,刚好标注在圆锥
tag.position.y += 80;

标签局部遮挡鼠标事件

标签<div id="tag"></div>在CSS3渲染器渲染的时候,默认会被设置为pointer-events: auto;,这时候虽然css3Renderer.domElement不遮挡canvas画布的鼠标事件,但是<div id="tag"></div>遮挡canvas画布的鼠标事件。

这时候你可以通过代码强制改变CSS3渲染器给标签设置的.style.pointerEvents = 'auto',设置为.style.pointerEvents = 'none',这时候注意一点,修改.style.pointerEvents,要在实例化new CSS3DObject(div)之后,因为执行new CSS3DObject(div)的时候,会把HTML标签设置为.style.pointerEvents = 'auto'

javascript
const div = document.getElementById('tag');
// HTML元素转化为threejs的CSS3模型对象
const tag = new CSS3DObject(div);
// new CSS3DObject(div);之后设置style.pointerEvents 
div.style.pointerEvents = 'none';

精灵模型Sprite作为标签

纹理贴图精灵模型

javascript
// 引入gltf模型加载库GLTFLoader.js
import {
    GLTFLoader
} from 'three/addons/loaders/GLTFLoader.js';

const loader = new GLTFLoader(); //创建一个GLTF加载器
const model = new THREE.Group();

loader.load("../工厂.glb", function (gltf) {
    model.add(gltf.scene);
    const texLoader= new THREE.TextureLoader();
    const texture = texLoader.load("./警告.png");
    const spriteMaterial = new THREE.SpriteMaterial({
      map: texture,
    });
    const sprite = new THREE.Sprite(spriteMaterial);
    // 控制精灵大小
    sprite.scale.set(5, 5, 1);
    sprite.position.y = 5 / 2; //标签底部箭头和空对象标注点重合  
    const obj = gltf.scene.getObjectByName('设备A标注');// obj是建模软件中创建的一个空对象
    obj.add(sprite);//tag会标注在空对象obj对应的位置
})

canvas贴图精灵模型

canvas画布作为CanvasTexture的参数创建一个纹理对象,本质上你可以理解为CanvasTexture把canvas画布当做图片,读取参数canvas画布上的像素值,创建纹理贴图Texture

javascript
loader.load("../工厂.glb", function (gltf) {
  model.add(gltf.scene);
  const canvas = createCanvas('设备A');//创建一个canvas画布
  // canvas画布作为CanvasTexture的参数创建一个纹理对象
  // 本质上你可以理解为CanvasTexture读取参数canvas画布上的像素值
  const texture = new THREE.CanvasTexture(canvas);
  const spriteMaterial = new THREE.SpriteMaterial({
    map: texture,
  });
  const sprite = new THREE.Sprite(spriteMaterial);
})

精灵模型Sprite和CSS3精灵模型CSS3DSprite标签差异

精灵模型渲染Sprite的标签,默认可以被其他网格模型遮挡,但是CSS3渲染器渲染的HTML元素标签是叠加在canvas画布上,不会被其它网格模型遮挡。