ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ThreeJS 测距功能

2021-01-28 14:03:24  阅读:910  来源: 互联网

标签:ThreeJS scene 功能 THREE let new line label 测距


文章目录

  测距功能,也就是选择两点,计算它们的距离,实现效果大致如下:

ranging

  上图中主要涉及几个操作:

  • 点击鼠标左键选点,点击鼠标右键停止选点,若选择点数超过两点,则两点绘制一条线段
  • 动态绘制线段
  • 动态绘制距离
  • 确定两点后将距离文字居中
  • 按下 ESC 键撤销上一步操作

选点绘线

  首先,我们需要通过鼠标在三维空间中选点,但是我们的屏幕是二维的,还有一维不知道,因此没办法直接凭空选点,因此目前的选点都是基于某个物体来的,即在物体上选点。

那么要如何获取鼠标点击的位置呢,首先需要知道标准设备坐标转空间坐标,然后使用 Raycaster 根据这个点从相机位置发出一条射线,并检测与这条射线相交的物体,即可获得鼠标点击的位置:

const mouse = new THREE.Vector2();

// 标准设备坐标转空间坐标
mouse.x = (e.clientX / width) * 2 - 1;
mouse.y = -(e.clientY / height) * 2 + 1;

let raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mouse, camera);

let intersects = raycaster.intersectObjects(scene.children);
if(intersects.length > 0) {
    return intersects[0].point;	// point 即点击坐标
}

  选了点后,需要在该点位置绘制一个圆点表示,这边使用了SphereGeometry 来绘制圆点:

createPoint = (pos) => {
    var mat = new THREE.MeshBasicMaterial({color: 0xff0000});
    var sphereGeometry = new THREE.SphereGeometry(0.3, 32, 32);
    var sphere = new THREE.Mesh(sphereGeometry, mat);
    sphere.position.set(pos.x, pos.y, pos.z);
    return sphere;
};

  两点之间绘制一条线段:

createLine = (p1, p2) => {
    let lineGeometry = new THREE.Geometry();
    let lineMaterial = new THREE.LineBasicMaterial({ color: 0x00ff00 });

    lineGeometry.vertices.push(p1, p2);
    let line = new THREE.Line(lineGeometry, lineMaterial);
    return line;
};

动态绘制线段和显示距离

  在选完起始点后,鼠标移动过程中需要动态绘制线段并显示当前位置和起始点的距离,距离计算使用 Vector3.distanceTo(vec) 即可,而动态效果则是不断重复的往场景中添加新的线段和文字移除旧的线段和文字。

  拆分一下,绘制线段已经有了,现在是创建 label 显示距离,label 的创建需要先使用 FontLoader 来制指定字体,再使用 TextBufferGeometry 来生成标签,下面是一些关键代码:

const loader = new THREE.FontLoader();
loader.load('https://raw.githubusercontent.com/mrdoob/three.js/master/examples/fonts/gentilis_regular.typeface.json', function(font) {
    this.font = font;
}.bind(this));


createLabel = (name, location) => {
    const textGeo = new THREE.TextBufferGeometry(name, {
        font: this.font,
        size: 0.8,
        height: 0.1,
        curveSegments: 1
    });

    const textMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff });
    const textMesh = new THREE.Mesh(textGeo, textMaterial);
    textMesh.position.copy(location);
    // 根据自己的坐标系设置进行旋转将文字水平显示
    textMesh.rotation.x = 0.5 * Math.PI;
    textMesh.rotation.y = Math.PI;

    return textMesh;
};

  在鼠标移动过程中绘制:

const p1 = points[points.length-1];
const mouse = new THREE.Vector2(
    (e.clientX / width) * 2 - 1, 
    -(e.clientY / height) * 2 + 1
);

let obj = this.getIntersects(mouse);

if (scene.getObjectByName('active-line')) {
    scene.remove(scene.getObjectByName('active-line'));
}

if (scene.getObjectByName('active-label')) {
    scene.remove(scene.getObjectByName('active-label'));
}

if (obj) {
    let line = this.createLine(p1.position, obj.point);
    line.name = 'active-line';
    scene.add(line);

    let dis = p1.position.distanceTo(obj.point).toFixed(2);
    let label = this.createLabel(dis + '', obj.point);
    label.name = 'active-label';
    scene.add(label);
}

文字居中

  知道了如何创建标签后,文字居中其实就很简单了,根据两个点的位置计算他们的中点,再在中点处添加标签即可:

let start = points[points.length-1];
let line = this.createLine(start.position, p.position);
let dis = start.position.distanceTo(p.position).toFixed(2);
let pos = new THREE.Vector3().copy(start.position);
pos.add(p.position).multiplyScalar(0.5);
let label = this.createLabel(dis + '', pos);

scene.add(line);
scene.add(label);

撤销操作

  使用 keydown 对键盘事件进行监听,当 event.key === Escape 时我们就撤销前面绘制的点和线和距离 label (如果有这些对象的话),也就是我们之前要使用一个数据结构,比如数组来保存我们添加到场景中的这些对象,然后根据添加顺序再一个个移除即可,因为主要就使用了 scene.remove 和顺序逻辑判断,这边就不贴代码了。

标签:ThreeJS,scene,功能,THREE,let,new,line,label,测距
来源: https://blog.csdn.net/qq_38701868/article/details/113335083

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有