three自带的框选工具SelectionBox、SelectionHelper

🧱 一、SelectionBox 是什么?

SelectionBox 是 Three.js 示例库中的一个工具类(examples/jsm/interactive/SelectionBox.js),
用于通过定义一个**三维空间包围盒(Box3)**来选中视野内的物体。

换句话说:

它根据相机、鼠标拖拽时的起点和终点,在 3D 世界中计算出被框选区域(视锥体内)的所有对象。

 

🌐 典型用法

import { SelectionBox } from 'three/examples/jsm/interactive/SelectionBox.js';

const selectionBox = new SelectionBox(camera, scene);
  • camera:用于确定视野。

  • scene:搜索物体的根节点。

  • 拖拽时更新起点/终点,再调用 selectionBox.select() 获取选中的对象列表。

 

📦 常用属性/方法

属性 / 方法 说明
startPoint 拖拽起点(NDC 坐标,即 -1~1)
endPoint 拖拽终点(NDC 坐标)
collection 当前选中的对象数组
select() 执行选择逻辑,返回选中的对象数组
updateFrustum() 更新内部视锥体,用于优化性能

🧩 二、SelectionHelper 是什么?

SelectionHelper 是用于辅助显示的一个小类(examples/jsm/interactive/SelectionHelper.js)。

它的作用是:在屏幕上画出一个矩形框(通过 <div> 叠加),显示鼠标框选范围。

它不参与 3D 计算,只负责 UI 层面的可视化。


🌐 用法示例

import { SelectionHelper } from 'three/examples/jsm/interactive/SelectionHelper.js';

const helper = new SelectionHelper(renderer, 'selectBox');
  • renderer:Three.js 渲染器,用来确定附着的 DOM。

  • 第二个参数 'selectBox' 是 CSS 类名(可用于自定义样式)。

SelectionHelper 会自动创建一个 <div class="selectBox">
并根据鼠标拖拽动态调整其位置和大小。

 

🧰 三、完整示例 — 鼠标框选物体

下面是一个完整、可运行的代码例子,展示如何结合两者实现框选高亮:

 
import * as THREE from 'three';
import { SelectionBox } from 'three/examples/jsm/interactive/SelectionBox.js';
import { SelectionHelper } from 'three/examples/jsm/interactive/SelectionHelper.js';

// 场景基础配置
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.set(0, 2, 5);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 添加地面与立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x0088ff });
for (let i = 0; i < 20; i++) {
  const cube = new THREE.Mesh(geometry, material.clone());
  cube.position.set(Math.random() * 8 - 4, 0.5, Math.random() * 8 - 4);
  scene.add(cube);
}

// 初始化 SelectionBox 与 Helper
const selectionBox = new SelectionBox(camera, scene);
const helper = new SelectionHelper(renderer, 'selectBox');

let selectedObjects = [];

function render() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}
render();

// 鼠标事件
function getNormalizedPosition(event) {
  return new THREE.Vector2(
    (event.clientX / window.innerWidth) * 2 - 1,
    -(event.clientY / window.innerHeight) * 2 + 1
  );
}

window.addEventListener('pointerdown', (event) => {
  for (const obj of selectedObjects) obj.material.color.set(0x0088ff); // 重置颜色
  selectedObjects = [];

  selectionBox.startPoint = getNormalizedPosition(event);
  selectionBox.endPoint = getNormalizedPosition(event);
});

window.addEventListener('pointermove', (event) => {
  if (helper.isDown) {
    selectionBox.endPoint = getNormalizedPosition(event);
    selectionBox.select(); // 实时更新选中
  }
});

window.addEventListener('pointerup', (event) => {
  selectionBox.endPoint = getNormalizedPosition(event);
  const allSelected = selectionBox.select();
  selectedObjects = allSelected;
  for (const obj of selectedObjects) obj.material.color.set(0xff8800);
});

🎨 CSS 样式(用于框选矩形)

.selectBox {
  border: 1px solid #55aaff;
  background-color: rgba(75, 160, 255, 0.1);
  position: fixed;
  pointer-events: none;
  z-index: 100;
}

🧠 四、交互逻辑总结

操作 功能
mousedown 记录起点、清空旧选中
mousemove 更新终点,更新 SelectionHelper
mouseup 获取选中对象、更新高亮

⚡ 五、扩展建议

  • 可以在 pointerup 事件中配合 OutlinePass 做选中高亮;

  • 或在场景中为选中对象添加包围框;

  • 若对象很多,建议限制参与检测的层级(例如仅检测 scene.children)。

posted @ 2025-10-17 10:38  SimoonJia  阅读(8)  评论(0)    收藏  举报