three.js 添加html内容、文本
需求:
1、在场景内添加html元素并动态更新
2、html内容需跟随场景变化
方案:
新加方案:https://www.zhihu.com/question/49929467/answer/118602848
1、在场景内创建一个模型点(多个模型点最好分组,方便管理)
2、获取到模型点
3、创建html元素
4、将html元素绑定到模型位置(将场景的3D坐标转为2D)
5、实时计算元素位置 (显示隐藏)
animate() { // 动画函数 this.render(); window.requestAnimationFrame(() => this.animate()); TWEEN.update(); this.orbitControls.update(); this.update(); // 更新点 }, LoadBox() { // 创建点。 this.groups = new THREE.Group(); this.groups.name = "btnlist"; for (let index = 0; index < this.nowfloat.length; index++) { const element = this.nowfloat[index].XYZ; console.log(element); let floorGeometry1 = new THREE.PlaneGeometry(1, 1, 1); var sphereMaterial = new THREE.MeshFaceMaterial({ color: 0xff00ff, // side: THREE.BackSide, // visible: false, }); var floorspheres = new THREE.Mesh(floorGeometry1, sphereMaterial); floorspheres.position.set( element.x, element.y + element.s / 2, element.z ); floorspheres.name = this.nowfloat[index].id; //default this.groups.add(floorspheres); } this.buffer_scene.add(this.groups); // this.render() }, update() { // 更新css2D内容位置 let halfWidth = window.innerWidth/2 ; let halfHeight = window.innerHeight/2; var btnlist = this.buffer_scene.getObjectByName("btnlist"); if (!btnlist) return; btnlist.traverse((e) => { var vector = e.position.clone().project(this.buffer_camera); var htmls = document.getElementsByClassName(e.name)[0]; if (htmls) { var left = vector.x * halfWidth + halfWidth; // + halfWidth var top = -vector.y * halfHeight + halfHeight; //+ halfHeight // console.log(vector.x,vector.y) if(vector.z >1){ htmls.style = 'display: none;'; }else{ htmls.style = `width:auto;display: flex;position: absolute;left:${ left }px;top:${top}px`; } } }); },
有几种方案
一、直接将文本P成为图片 然后在场景内加载 2D模型将该图片当作模型贴图处理
二、将html内容通过canvas 然后再以模型的方式加载进场景(不做详细解释)
1、创建
getTextCanvas(text){ // 创建贴图文字 var width=512, height=256; var canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; var ctx = canvas.getContext('2d'); ctx.fillStyle = '#008080'; ctx.fillRect(0, 0, width, height); ctx.font = 50+'px " bold'; ctx.fillStyle = '#FFFFFF'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(text, width/2,height/2); return canvas; },
2、加载
var geometry = new THREE.PlaneGeometry(e.w, e.h, 30 ); var material = new THREE.MeshBasicMaterial( { // map:new THREE.CanvasTexture(this.getTextCanvas(e.content)), // canvas 画图方式 map:new THREE.TextureLoader().load(`${this.GLOBAL.service}img/043img/btn/${e.content}.png`), } ); var introduce = new THREE.Mesh( geometry, material ); introduce.name= "model introduce" // plane.location=i.location introduce.modeltype= 3 // introduce.position.set(x,y,z); introduce.lookAt(0,y,0) skyBox.add(introduce);
三、用CSS2DObject进行处理
1、增加渲染器 CSS2DRenderer
2、使用 three.js 的 CSS2DObject 模块 进行html内容转换 并绑定模型
一般需要这个功能的肯定都不是新手了,所以内容就不做介绍了,这里只需要关注几点
1、增加渲染器(原有的渲染器不动,新增一个CSS2DRenderer渲染器 ):
addhtml() { // 场景渲染器 this.renderer = new THREE.WebGLRenderer(); this.renderer.shadowMapEnabled = true; this.renderer.shadowMap.type = THREE.PCFSoftShadowMap; // this.renderer.gammaOutput = true; this.renderer.gammaFactor = 2.2; // this.renderer.setClearColor(new THREE.Color(0xcce0ff)); this.renderer.setSize(window.innerWidth*0.95, window.innerHeight*0.95); document .getElementById("container") .appendChild(this.renderer.domElement); // window.addEventListener("resize", () => this.onWindowResize()); this.labelRenderer = new CSS2DRenderer(); // 新增的渲染器 this.labelRenderer.setSize(window.innerWidth*0.95, window.innerHeight*0.95); // this.labelRenderer.domElement.style.position = 'absolute'; // this.labelRenderer.domElement.style.top = 0; this.labelRenderer.domElement.style="pointer-events: auto;position: absolute;top: 0px;" // 处理新的渲染器 document.getElementById("container").appendChild(this.labelRenderer.domElement); },
animate() { // 渲染 this.renderer.render(this.scene, this.camera); this.labelRenderer.render(this.scene, this.camera);// 加载新渲染器 window.requestAnimationFrame(() => this.animate()); TWEEN.update(); },
注意:官网示例只适应于全屏的情况 不全屏的情况请自行调整
2、增加内容容器:
<template> <div class="project"> <div id="text" style=" position: relative;width: 30%; height: 100px; color: #fff;"> {{modelnumber}} </div> <div id="container"> </div> </template>
3、绑定模型(创建模型什么的这里就不解释了):
// 2D 文本 // let laberDiv = document.createElement('div');//创建div容器 let laberDiv = document.getElementById('text');//获取div容器 // laberDiv.innerHTML=` // <div class="leftTip" style=""> // ${this.modelnumber} // </div> // `; laberDiv.style.marginTop = '-1em'; let pointLabel = new CSS2DObject(laberDiv); pointLabel.position.set(0,100,0); // 相对模型的位置 console.log(pointLabel) skyBox.add(pointLabel); //绑定到模型
也看到了,你也可以选择直接新建一个容器、但是我尝试的时候内容无法动态变化、如果你不需要动态变化也可以直接新建
找资料的时候看到一个问题(没有尝试)、创建的这个容器切换场景不会消失、需要注意处理、这个创建出来的不在模型列表内、而是在dom里面、所以遇到这个情况、请尝试直接处理dom
效果:
注:
前面两种方式是直接在场景内加载一个模型、第三种方式是将元素绑定在模型上