threejs模型指定位置打一个永远面向正面的标签

一、实现目标

基于一个3D模型,实现在3D模型中某些固定位置做指向性标注的功能。

 (配色真丑不过可以突出目标,凑合看看)

 (转动各个角度也是指向该位置的)

例如,在一个柜子的3D模型里,需要在指向柜子底部的位置,标注一个柜子底部高度的信息

二、实现思路

1、在3D模型的画布层上再叠加一层页面元素显示标注

2、使用 threejs的CSS2DRenderer执行3D模型的位置到页面元素位置的转换(将页面元素能够渲染到3D模型的执行位置)

3、在threejs的渲染动画animate函数中每一帧重新渲染页面元素,保证在拖动放大等操作后,元素依旧跟随该指向的固定点,标注信息以及文字也一直面向正面。但是,这里要提,在实现过程中发现,使用animate动画每一帧重复渲染,过度消耗性能,因此找到了threejs的变化事件,监听相机的change事件时,重新渲染页面元素标签,同样能够达到在3D模型拖拽变化时,标签指向位置保持正确

三、实现代码

1、加载页面要展示的3d模型文件并渲染完成之后,执行initMeshRender函数,初始CSS2DRenderer对象,并把元素push到页面。

2、初始完成执行addLabel添加点位函数,传入所有标点的数组位置和名称。

3、绘制点位时,先清除掉之前的全部点位,避免页面元素叠加重复消耗性能。

4、初始化代码中定义控制器,监听相机变动,调用addLabel函数重绘点位。

 initMeshRender() {
      const param = 页面存储数据的对象,container为页面主体元素
      //初始化渲染
      labelRenderer = new CSS2DRenderer();
      param.container = document.getElementById(`container${this.currentKey}`)
      labelRenderer.setSize(param.container.clientWidth, param.container.clientHeight);
      labelRenderer.domElement.style.position = 'absolute';
      labelRenderer.domElement.style.top = '0px';
      labelRenderer.domElement.id = 'CSS2DRenderer';
      param.container.appendChild(labelRenderer.domElement);

      this.addLabel();
    },
    addLabel() {
      this.setPosMesh([{pos:{x: 100, y: 50, z: 100}, name: "测试222"}])
    },
    setPosMesh(posArr) {

      function removeTag() {
        //移除所有标签
        groupPosTag ? groupPosTag.children.forEach(f=>{
          groupPosTag.remove(f);
        }) : '';
        scene.remove(groupPosTag)
        let r = document.getElementById('CSS2DRenderer');
        if (r) {
          r.innerHTML = "";
        }
      }

      let addPos =(obj)=>{
        let name = obj.name;
        let pos = obj.pos;
      
        //创建测点显示标签
        let falanpos = new THREE.Mesh();
       
        groupPosTag.add(falanpos);//mesh添加到场景
        const posDiv = document.createElement('div');
        posDiv.className = 'wind_falan_posBg';
        //背景图自定义标签
        let bg = document.createElement('div')
        bg.className = 'bg';
        posDiv.appendChild(bg);
        //标签指向线
        let line = document.createElement('div')
        line.className = 'line';
        posDiv.appendChild(line);
        //文字
        let text = document.createElement('div')
        text.className = 'text';
        text.textContent = name;
        posDiv.appendChild(text);


        const falanposLabel = new CSS2DObject(posDiv);
        falanposLabel.position.set(pos.x, pos.y, pos.z);
        falanpos.add(falanposLabel);
        falanposLabel.layers.set(0);
        falanposLabel.name = 'wind_falan_posBg';
        groupPosTag.add(falanposLabel);
        divArr.push(posDiv)


      }

      let divArr = [];
      removeTag();
      posArr.forEach(f=>{
        addPos(f)
      })

      scene.add(groupPosTag);
      labelRenderer.render(scene, camera);

      divArr.forEach(posDiv=>{
        let r = posDiv.getBoundingClientRect(), offset = 0;
        if (r) {
          offset = r.width / 2;
        }
        posDiv.style.marginLeft = (offset + 35) + 'px';//x偏移计算
      })

    },
     //初始化控制器
      controls = new OrbitControls(camera, param.container)
      controls.addEventListener('change', () => {
     
        this.addLabel();//重绘标签,保证标签在转动时点位正确
      })

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值