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

 

效果:

 

注:

前面兩種方式是直接在場景內加載一個模型、第三種方式是將元素綁定在模型上

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM