需求:
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
效果:
注:
前面兩種方式是直接在場景內加載一個模型、第三種方式是將元素綁定在模型上