Three.js 线段测量

提示词

PROMPT
1
使用 Three.js 创建线段测量效果,使用 TransformControls 和 Raycaster 实现线段测量功能。

效果描述

这是一个展示如何创建线段测量效果的示例,使用 TransformControls 和 Raycaster 实现线段测量功能。

效果特性

  • 线段测量:创建线段测量
  • TransformControls:使用 TransformControls
  • Raycaster:使用 Raycaster
  • 距离计算:计算线段距离
  • 标记点:显示标记点
  • 距离显示:显示距离信息

核心参数

参数 说明
标记点数量 可变 标记点数量
线段颜色 可变 线段颜色
标记点大小 可变 标记点大小
距离单位 px 距离单位
网格大小 40 网格大小

核心代码解析

坐标转换

JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
const worldToScreenPosition = (pos, camera) => {
    const worldVector = new THREE.Vector3(pos.x, pos.y, pos.z);
    const standardVector = worldVector.project(camera);
    const widthHalf = window.innerWidth / 2;
    const heightHalf = window.innerHeight / 2;
    return {
        x: Math.round(standardVector.x * widthHalf + widthHalf),
        y: Math.round(-standardVector.y * heightHalf + heightHalf),
        z: 1,
    };
}

创建标记点

JAVASCRIPT
1
2
3
4
5
6
7
function createMarker(position) {
    const geometry = new THREE.SphereGeometry(0.2, 16, 16);
    const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
    const marker = new THREE.Mesh(geometry, material);
    marker.position.copy(position);
    return marker;
}

创建线段

JAVASCRIPT
1
2
3
4
5
6
7
function createLine(point1, point2) {
    const points = [point1, point2];
    const geometry = new THREE.BufferGeometry().setFromPoints(points);
    const material = new THREE.LineBasicMaterial({ color: 0x0000ff });
    const line = new THREE.Line(geometry, material);
    return line;
}

创建距离标签

JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function createDistanceLabel(point1, point2, distance) {
    const midPoint = new THREE.Vector3().addVectors(point1, point2).multiplyScalar(0.5);
    const screenPos = worldToScreenPosition(midPoint, camera);
    
    const label = document.createElement('div');
    label.className = 'distance-label';
    label.style.position = 'absolute';
    label.style.left = screenPos.x + 'px';
    label.style.top = screenPos.y + 'px';
    label.style.color = '#000';
    label.style.backgroundColor = 'rgba(255, 255, 255, 0.8)';
    label.style.padding = '5px 10px';
    label.style.borderRadius = '5px';
    label.textContent = distance.toFixed(2) + ' px';
    
    document.body.appendChild(label);
    return label;
}

鼠标点击事件

JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
window.addEventListener('click', (event) => {
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    
    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObject(plane);
    
    if (intersects.length > 0 && canDrawLine) {
        const point = intersects[0].point;
        const marker = createMarker(point);
        markersGroup.add(marker);
        markers.push(marker);
        points.push(point);
        
        if (points.length > 1) {
            const prevPoint = points[points.length - 2];
            const line = createLine(prevPoint, point);
            scene.add(line);
            
            const distance = prevPoint.distanceTo(point);
            distanceArray.push(distance);
            totalDistance += distance;
            
            const label = createDistanceLabel(prevPoint, point, distance);
            distanceDom = label;
        }
    }
});

技术亮点

  1. 线段测量:创建线段测量
  2. TransformControls:使用 TransformControls
  3. Raycaster:使用 Raycaster
  4. 距离计算:计算线段距离
  5. 标记点:显示标记点

调试技巧

  1. 标记点大小:调整标记点大小改变显示
  2. 线段颜色:调整线段颜色改变显示
  3. 网格大小:调整网格大小改变显示
  4. 距离单位:调整距离单位改变显示
  5. 标签样式:调整标签样式改变显示

扩展方向

  1. 复杂测量:创建更复杂的测量
  2. 动画效果:添加动画效果
  3. 交互控制:添加交互控制
  4. 多种测量:支持多种测量
  5. 自定义样式:支持自定义样式

本文档由 ThreeLab 编辑整理,如需转载,请注明出处。