前言

一开始做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/