之前我们实现threejs 太阳系提高性能 共享Geometry Material,接下来我们给星球来添加文字标注。给星球添加文字标注就是通过css2d给模型添加标注
给星球添加文字标签,我们使用css2d来实现。
标签方法
首先我们创建一个标签方法,用来接收名称
function tag(name) {
var that = this;
// 创建div元素(作为标签)
var div = document.createElement('div')
div.innerHTML = `<div class="tags">${name}</div>`
div.classList.add('tag')
//div元素包装为CSS2模型对象CSS2DObject
var label = new CSS2DObject(div)
div.style.pointerEvents = 'none'//避免HTML标签遮挡三维场景的鼠标事件
return label//返回CSS2模型标签
}
创建css2d渲染器
创建一个css2d渲染器,用来渲染我们创建的标签
// 标签创建
var labelRenderer = new CSS2DRenderer()
labelRenderer.setSize(window.innerWidth, window.innerHeight)
labelRenderer.domElement.style.position = 'absolute'
// 相对标签原位置位置偏移大小
labelRenderer.domElement.style.top = '0px'
labelRenderer.domElement.style.left = '0px'
// //设置.pointerEvents=none,以免模型标签HTML元素遮挡鼠标选择场景模型
labelRenderer.domElement.style.pointerEvents = 'none'
将这个渲染器插入到div中
that.$refs.home.appendChild(labelRenderer.domElement)
创建模型时连同标签一起插入
我们在创建星球的时候,创建标签,将星球添加到场景后,在通过getObjectByName方法来获取场景中星球的3维坐标,使用getWorldPosition将3维坐标转为世界坐标。赋值给标签,然后插入到场景中。并将这些tag标签单独加入一个数组中,以便于后期我们更新标签坐标做准备。
this.list.forEach((type, index) => {
var mesh = addGeoMetry(geometry, type.URL, type.R)
mesh.name = type.name
mesh.data = type
mesh.angle = 2 * Math.PI * Math.random();
scene.add(mesh); //网格模型添加到场景中
// 添加标签
var group = scene.getObjectByName(type.name)
var label = tag(group.name)//把名称obj.name作为标签
var pos = new THREE.Vector3()
group.getWorldPosition(pos)//获取obj世界坐标、
label.position.copy(pos)//标签标注在obj世界坐标
label.name = group.name
scene.add(label)//标签插入model组对象中
that.labelLst.push(label)
// 添加标签
// 创建轨道
if (type.revolutionR) {
var line = circle(lineGeometry, material, type.revolutionR)
scene.add(line)
}
});
渲染
因为添加了css2d渲染器,所以我们需要将css2d也加入渲染函数中。
renderer.render(scene, camera); //执行渲染操作
labelRenderer.render(scene, camera); //执行渲染标签层
在这里我们除了要更新星球的坐标,也需要更新标签的位置,在遍历更新星球时,我们也通过这个星球的名称来获取对应名称的css2d标签并更新其坐标
that.labelLst.forEach((type2) => {
if (type2.name == type.name) {
type2.position.set(x, 0, z);
}
});
render渲染方法完整
function render() {
scene.children.forEach((type) => {
if (type.type == 'Mesh') {
type.rotateY(0.01)
type.angle += 0.01;// 每次执行render角度新增加
var x = type.data.revolutionR * Math.sin(type.angle);//地球x坐标计算
var z = type.data.revolutionR * Math.cos(type.angle);//地球z坐标计算
// 设置地球xz坐标,实现公转动画
type.position.set(x, 0, z);
that.labelLst.forEach((type2) => {
if (type2.name == type.name) {
type2.position.set(x, 0, z);
}
});
}
});
renderer.render(scene, camera); //执行渲染操作
labelRenderer.render(scene, camera); //执行渲染标签层
requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
}
效果演示
演示地址
视频课程介绍
当前笔记是Three.js太阳系案例 threejs视频教程 星球和太阳添加标签 学习实践笔记