Three.js 中计算两个物体之间的距离

358 阅读3分钟

在 3D 场景开发中,计算两个物体之间的距离是常见需求。无论是实现碰撞检测、AI 行为逻辑,还是创建视觉特效,距离计算都是基础且关键的功能。本文将详细介绍在 Three.js 中如何计算两个物体之间的距离。

基本概念

在 Three.js 中,物体之间的距离通常指的是它们位置 (position) 之间的欧几里得距离。每个 Three.js 对象都有一个 position 属性,它是一个 Vector3 实例,表示该对象在 3D 空间中的坐标 (x, y, z)。

计算距离的方法

Three.js 的 Vector3 类提供了多种计算距离的方法:

  1. distanceTo () - 计算当前向量到另一个向量的距离
  1. distanceToSquared () - 计算距离的平方 (性能更好,适用于比较距离大小的场景)

下面是一个简单的示例,展示如何使用这些方法:

// 假设我们有两个Three.js对象
const object1 = new THREE.Mesh(geometry, material);
const object2 = new THREE.Mesh(geometry, material);
// 设置它们的位置
object1.position.set(10, 5, 0);
object2.position.set(4, 1, 0);
// 计算它们之间的距离
const distance = object1.position.distanceTo(object2.position);
console.log('两个物体之间的距离是:', distance); // 输出约为7.21
// 如果只需要比较距离大小,可以使用distanceToSquared()
const distanceSquared = object1.position.distanceToSquared(object2.position);
console.log('距离的平方是:', distanceSquared); // 输出约为52

应用示例:距离检测系统

下面是一个完整的示例,展示如何实现一个简单的距离检测系统。当两个物体之间的距离小于某个阈值时,我们会改变它们的颜色。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Three.js 距离检测示例</title>
    <script src="https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js"></script>
</head>
<body>
    <script>
        // 创建场景、相机和渲染器
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);
        // 创建两个立方体
        const geometry = new THREE.BoxGeometry(1, 1, 1);
        
        // 物体1 - 红色立方体
        const material1 = new THREE.MeshBasicMaterial({ color: 0xff0000 });
        const object1 = new THREE.Mesh(geometry, material1);
        object1.position.set(-3, 0, 0);
        scene.add(object1);
        
        // 物体2 - 蓝色立方体
        const material2 = new THREE.MeshBasicMaterial({ color: 0x0000ff });
        const object2 = new THREE.Mesh(geometry, material2);
        object2.position.set(3, 0, 0);
        scene.add(object2);
        // 添加坐标轴辅助
        const axesHelper = new THREE.AxesHelper(5);
        scene.add(axesHelper);
        // 设置相机位置
        camera.position.z = 5;
        // 距离阈值
        const distanceThreshold = 4;
        // 创建一个标签显示距离
        const distanceLabel = document.createElement('div');
        distanceLabel.style.position = 'absolute';
        distanceLabel.style.top = '10px';
        distanceLabel.style.left = '10px';
        distanceLabel.style.color = 'white';
        distanceLabel.style.fontFamily = 'Arial';
        distanceLabel.style.fontSize = '16px';
        document.body.appendChild(distanceLabel);
        // 动画循环
        function animate() {
            requestAnimationFrame(animate);
            // 让物体2向物体1移动
            object2.position.x -= 0.01;
            
            // 如果物体2移动到左边太远,则重置位置
            if (object2.position.x < -5) {
                object2.position.x = 3;
            }
            // 计算两个物体之间的距离
            const distance = object1.position.distanceTo(object2.position);
            
            // 更新标签显示
            distanceLabel.textContent = `距离: ${distance.toFixed(2)} (阈值: ${distanceThreshold})`;
            // 当距离小于阈值时,改变颜色
            if (distance < distanceThreshold) {
                object1.material.color.set(0x00ff00);
                object2.material.color.set(0x00ff00);
            } else {
                object1.material.color.set(0xff0000);
                object2.material.color.set(0x0000ff);
            }
            renderer.render(scene, camera);
        }
        animate();
    </script>
</body>
</html>

在这个示例中,我们创建了两个立方体,一个红色一个蓝色。蓝色立方体会自动向红色立方体移动,我们实时计算它们之间的距离并显示出来。当距离小于设定的阈值时,两个立方体都会变成绿色。

性能优化

在处理大量对象的场景中,计算每个对象之间的距离可能会影响性能。以下是一些优化建议:

  1. 使用 distanceToSquared () 代替 distanceTo (),避免开平方运算
  1. 实现空间分区算法 (如八叉树) 来减少需要计算距离的对象数量
  1. 限制距离计算的频率,不必每帧都计算

更复杂的距离计算

在某些情况下,你可能需要计算更复杂的距离,比如:

  1. 从一个点到一个物体表面的距离
  1. 两个物体边界框之间的距离
  1. 两个物体碰撞体之间的最小距离

对于这些情况,Three.js 提供了 Box3、Sphere 等类,它们也有类似的 distanceTo 方法。你还可以使用 Raycaster 来计算点到物体表面的距离。

通过掌握这些技术,你可以在 Three.js 中实现各种复杂的交互和效果,从简单的距离提示到高级的物理模拟。