关于前端:ThreeJS学习记录四使用CSS2DRenderer设置html标签并始终正向面向摄像机

3次阅读

共计 2660 个字符,预计需要花费 7 分钟才能阅读完成。

前言

一开始做 3D 视图的时候,遇到须要定位加标签的需要——我是间接加 TextGeometry,因为须要汉字,加载了很大的字体包,对性能来说十分不敌对。而且他不能跟着鼠标旋转挪动而始终正向面对用户,成果不难看。前面学到了 threejs 是反对与 HTML 标签联合的,所以有了这篇文章。

成果

其中蓝色柱体是 blender 的 gltf 模型,在 blender 里的坐标和名称,threejs 都能够获取到。

实现

CSS2DRenderer 是 CSS3DRenderer(CSS 3D 渲染器)的简化版本,惟一反对的变换是位移。

如果你心愿将三维物体和基于 HTML 的标签相结合,则这一渲染器将非常有用。在这里,各个 DOM 元素也被蕴含到一个 CSS2DObject 实例中,并被增加到场景图中。

首先是 DOM:你能够写 DOM,前面获取一下,也能够创立 dom。

<!--tagArray 是标签数组,须要获取设置一下。也能够创立 dom,不写在这 -->
<div
      :class="['tag', tag]"
      v-for="tag in tagArray"
      :key="tag"
    >
      <div class="tag__content">
        <span class="tag__txt">{{tag}}</span>
      </div>
    </div>

上面是 JS 局部,次要代码就是这些,其它必要的渲染器创立没写了。

<script>
import * as THREE from 'three'
// threejs CSS3DSprite 精灵模型标注模型
import {CSS2DRenderer, CSS2DObject} from 'three/examples/jsm/renderers/CSS2DRenderer.js'


// 创立 CSS2DRenderer(这一部分紧接着 renderer 的创立之后)
this.labelRenderer = new CSS2DRenderer()
this.labelRenderer.setSize(window..width, window..height)
this.labelRenderer.domElement.style.position = 'absolute'
this.labelRenderer.domElement.style.top = '0px'
this.DOM.appendChild(this.labelRenderer.domElement)


// 创立标签(独自进去的一个办法,上面调用了)newTag(name){const labelOne = document.getElementsByClassName(name)[0]
    const labelObjOne = new CSS2DObject(labelOne)
    return labelObjOne
}


//labelObjOne 就是创立的对象,之后就退出 scene 并定位就行了,我这里是与 Blender 导出的 gltf 模型放弃一样的地位,参考代码如下:loader.load(
        '/provinceMap.gltf',
        gltf => {console.log('控制台查看加载 gltf 文件返回的对象构造', gltf)
          console.log('gltf 对象场景属性', gltf.scene)

          gltf.scene.position.set(0, 0, 0)
          this.scene.add(gltf.scene)

          // 循环 gltf 外面的 children,每个柱体都须要配上标签
          gltf.scene.children.forEach(mesh => {if (mesh.type === 'Mesh' && mesh.name.indexOf('柱体') != -1) {const label = this.newTag(mesh.name) // 把 mesh 名称作为标签
              // 增加 label 坐标
              const pos = new THREE.Vector3()
              mesh.getWorldPosition(pos) // 获取 obj 世界坐标
              label.position.copy(pos) // 标签标注在 obj 世界坐标
              this.scene.add(label)
            }
          })
          // 执行渲染操作
          this.renderer.render(this.scene, this.camera)
        },
        xhr => {console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
        },
        error => {console.error(error)
        }
      )
</script>

这里附上 tag 标签的款式

<style lang="less" scoped>
.tag,
.tag__dot {display: inline-flex;}
.tag {
  position: fixed;
  cursor: pointer;
}
.tag__dot {
  align-items: center;
  transform: rotate(-45deg);
}
.tag__dot:before {
  width: 0.42vw;
  height: 0.42vw;
  border-radius: 50%;
  border: 0.1vw solid #000;
  content: '';
}
.tag__dot:after {
  width: 1.82vw;
  height: 1px;
  background: #000;
  content: '';
}
.tag__content {
  display: flex;
  align-items: center;
  position: relative;
  top: -0.94vw;
  height: 1.88vw;
  // margin-left: -0.42vw;
  background: rgba(0, 0, 0, 0.5);
  border-radius: 1.88vw;
  padding: 0 1.04vw;
}
.tag__txt {
  white-space: nowrap;
  font-size: 12px;
  color: #fff;
  &:hover {color: #fff;}
}
</style>

总结

性能完满实现啦,就是款式有点丑。接下来就能够在标签上绑定点击事件,点击后相机通过动画迟缓挪动到指标点,实现具体查看。这里就须要用到 tween.js。不过我发现 …. 如果是地图上加几个 3D 物体和 2D DOM,间接 AntV L7 他不香吗???

附录

官网的 CSS2DRenderer 例子:https://threejs.org/examples/#css2d_label
加载 blender 导出的 gltf 模型教程:http://www.webgl3d.cn/pages/006fcb/

正文完
 0