three 实现悬浮提示框效果
提示: 我现在这边是用的vue2.0的项目来使用的three
1.事前了解
对于悬浮提示框,官方提供了好几种做法。精灵图等做法。
而我选了CSS3DObject,把一个CSS元素转化成一个three的3D对象插入到场景中
需要用到以下的库CSS3DRenderer,CSS3DObject.
- CSS3DObject把一个文档dom对象转化成three可用的Object3D对象
- CSS3DRenderer就是负责渲染这个CSS3DObject的渲染器
思路如下
- 新生成一个scene对象
- 生成对应的DOM元素
- 然后使用CSS3DObject生成对应的Object3D对象
- 再设置好Object对象属性
- 往scene里面添加这个Object3D对象
- 新的scene对象将在CSS3DRenderer里面渲染
2.编写函数
先引用我们所需要用到的函数库
//CSS3D
import {
CSS3DRenderer,
CSS3DObject,
} from "three/examples/jsm/renderers/CSS3DRenderer.js";
为了代码的美观,我把生成DOM节点对象单独拉出来写成了一个函数
//生成CSS对象
createdCSS3DLabel() {
//增加一个CSS3D对象
let element = document.createElement("div");
element.className = "css3dcontain";
element.style.opacity = 0.75;
let lableTitle = document.createElement("div");
lableTitle.className = "css3dTitle";
// lableTitle.style.opacity = 0.75;
lableTitle.textContent = "数据详情:";
element.appendChild(lableTitle);
let lableItem = document.createElement("div");
lableItem.className = "css3dItem";
lableItem.style.opacity = 0.75;
let lableLeft = document.createElement("div");
lableLeft.className = "css3dLeft";
lableLeft.textContent = "风速";
// lableLeft.style.opacity = 0.75;
let lableRight = document.createElement("div");
lableRight.className = "css3dRight";
// lableRight.style.opacity = 0.75;
lableRight.textContent = "3.7m/s";
lableItem.appendChild(lableLeft);
lableItem.appendChild(lableRight);
element.appendChild(lableItem);
return element;
},
现在把renderer添加到效果组合器中
在用场景对象和相机对象新生成一个renderpass渲染通道。这个对象会渲染场景但是不会输出图像。但是图像是多个通道组合输出的,这个必不可少
再去修改循环渲染函数
//循环渲染函数
render() {
//用效果合成器渲染
this.composer.render();
//使用刷新率刷新动画 流畅
requestAnimationFrame(this.render);
//得到时间差
var delta = this.clock.getDelta();
if (this.mixer != null) {
//更新动画
this.mixer.update(delta);
}
},
渲染器方法
我们的CSS3DObject是需要单独在CSS3DRenderer上渲染的。
所以我继续重新生成一个新的scene对象,专门用于存渲染我们CSS3DObject的对象。
再新建出一个CSS3DRenderer。这个渲染器和我们普通的渲染器一样使用。three支持多个渲染器同时渲染。
//CSS3D标签要单独设置
//新增一个场景
this.scene2 = new THREE.Scene();
//新开一个3D渲染器
this.render3D = new CSS3DRenderer();
//设置渲染器大小
this.render3D.setSize(
document.getElementById("webgldiv").clientWidth,
document.getElementById("webgldiv").clientHeight
);
//需要设置位置
this.render3D.domElement.style.position = "absolute";
this.render3D.domElement.style.top = 0;
document.getElementById("webgldiv").appendChild(this.render3D.domElement);
//该渲染器也要加上同样的控制器
new OrbitControls(this.camera, this.render3D.domElement);
如果你加了控制器,在这个渲染器也要加上。要不然你发现你没法移动
接下来我们再循环渲染函数中添加上我们的CSS3DRenderer渲染器
//循环渲染函数
render() {
//用效果合成器渲染
this.composer.render();
//CSS3D渲染对象
this.render3D.render(this.scene2, this.camera);
//使用刷新率刷新动画 流畅
requestAnimationFrame(this.render);
//得到时间差
var delta = this.clock.getDelta();
if (this.mixer != null) {
//更新动画
this.mixer.update(delta);
}
},
再次修改我们的点击函数。实现点击后高亮,同时生成一个标签。
//鼠标点击效果
window.addEventListener(
"click",
(event) => {
//保持原事件
event.preventDefault();
let selectedObject = null;
//获得射线得到的线路上的全部物体
//layerX layerY 元素设置了定位后是点击相对于元素的定位
var intersects = this.getIntersects(event.layerX, event.layerY);
//分类
if (intersects.length > 0) {
//生成CSSDOM对象
let element = this.createdCSS3DLabel();
//把生成的CSSDOM对象处理成three的节点对象
let css3DObject = new CSS3DObject(element);
//设置CSS3DObject对象
css3DObject.position.x = 180 + intersects[0].object.position.x * 2500;
css3DObject.position.y = intersects[0].object.position.y * 2500;
css3DObject.position.z = intersects[0].object.position.z * 2500;
//在第二个场景中添加这个对象
this.scene2.add(css3DObject);
//把点击的对象塞入渲染器
this.outlinePass.selectedObjects = [intersects[0].object];
}
},
false
);