开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情
之前老是被小伙伴问到这个问题,就是怎么把三维场景的mesh和css3d的dom信息展示框之间做一个线的对应连接。今天就把这个问题在这里,将这个问题一步步解析。
首先
我们需要了解一下世界坐标和相对坐标这个概念,接下来的处理才会容易。 大家都知道想要画一条线,那么我们需要线段的两端的坐标(3维空间的世界坐标),线段的一头是连接在threejs世界坐标系中的mesh的世界坐标(如果想在模型的对应位置的连接处做对应处理,也可以通过配置不同模型的位移来实现),这个我们是肯定有具体的数值的。那么我们只需要线段的另一端坐标就可以了。
信息框
我们一般用css2dObject或者css3dObject来做信息框,加到3维世界中。 我们当然可以之间在加入模型的时候,把信息框的坐标也一起加入(加个偏移量,形场一个距离)。但是这样会不跟随目标移动。用来连接线段,也会被拉长。所以,我们就需要接下来的处理:
有的同学可能会说,我更新mesh的坐标的时候,再更新信息框的坐标。这样不就可以了吗?确实可以,但是如果有更好的方式,何乐而不为呢?
这里介绍一个小技巧:
由于threejs的Mesh类是继承Object3D类的,那么我们可以直接把信息框当作mesh的children加入进去。这样threejs就会自动维护信息框的坐标变换。那么我们的线段,实现的基础也就有了。
线段
能偷懒还是要偷懒的,这里我们直接把线段也加到mesh中。这样线段的两端坐标直接就可以计算出了。
一段为(0,0,0),另一端为(偏移量X,偏移量Y,偏移量Z)。那么,这个基本上就实现了。 接下来就是无聊的敲代码时间~~
代码
//Mesh
const geometry = new THREE.CylinderGeometry(50, 50, 20, 32);
const material = new THREE.MeshBasicMaterial({ color: 0xffff00 });
const cylinder = new THREE.Mesh(geometry, material);
// // 1.头部信息框
const objectCSS = new CSS3DSprite(this.addElement());
objectCSS.scale.set(1, 1, 1);
cylinder.add(objectCSS);
objectCSS.position.set(
position.x,
position.y + (height * 3) / 4,
position.z
);
//2. 虚线连接
const points = [];
points.push(position.x, position.y + (height * 3) / 4, position.z);
points.push(0, 10 + height / 4, 0); //偏移量
const frameGeometry = new LineGeometry();
frameGeometry.setPositions(points);
const frameMaterial = new LineMaterial({
color: 0xffffff,
linewidth: 2,
dashed: true,
dashSize: 8,
gapSize: 2,
dashScale: 1,
worldUnits: true,
});
frameMaterial.resolution.set(window.innerWidth, window.innerHeight);
const frameLine = new Line2(frameGeometry, frameMaterial);
frameLine.computeLineDistances();
// 3.底部球
this.lineAndDot = new THREE.TextureLoader().load(
'https://img95.699pic.com/element/40114/0827.png_860.png'
);
const materialB = new THREE.SpriteMaterial({
map: this.lineAndDot,
transparent: true,
});
const spriteB = new THREE.Sprite(materialB);
const geometryB = new THREE.CircleGeometry(height / 4, 32);
spriteB.geometry = geometryB;
spriteB.position.set(0, 10 + height / 4, 0);//偏移量
cylinder.add(spriteB);
cylinder.add(frameLine);
cylinder.renderOrder = 10;
this.scene.add(cylinder);
结束
那么,这个问题就算解决了。如果还有其他问题,欢迎评论区留言。
照例贴个链接。拜拜了您嘞~