6.4交互 (Interaction)


文档摘要

6.4交互 (Interaction) 6.4 Three.js 中的交互 (Interaction) 在 Three.js 中,交互是指用户通过鼠标、键盘、触摸等方式与 3D 场景进行互动。交互性是提升用户体验的关键,使场景更加生动和引人入胜。本节将深入探讨 Three.js 中交互的实现方式,包括事件监听、射线投射、对象选择和控制等。 6.4.1 事件监听 Three.js 本身并不直接处理 DOM 事件。我们需要利用 JavaScript 的原生事件监听机制,然后将事件信息转换为 Three.js 可以理解的形式。 6.4.2 射线投射 (Raycasting) 射线投射是实现 3D 交互的核心技术。它模拟从相机发射一条射线,检测该射线与场景中物体的相交情况。

6.4交互 (Interaction)

6.4 Three.js 中的交互 (Interaction)

在 Three.js 中,交互是指用户通过鼠标、键盘、触摸等方式与 3D 场景进行互动。交互性是提升用户体验的关键,使场景更加生动和引人入胜。本节将深入探讨 Three.js 中交互的实现方式,包括事件监听、射线投射、对象选择和控制等。

6.4.1 事件监听

Three.js 本身并不直接处理 DOM 事件。我们需要利用 JavaScript 的原生事件监听机制,然后将事件信息转换为 Three.js 可以理解的形式。

// 获取渲染器 DOM 元素 const rendererDom = renderer.domElement; // 监听鼠标移动事件 rendererDom.addEventListener('mousemove', (event) => { // 获取鼠标在 canvas 上的标准化坐标 mouse.x = (event.clientX / rendererDom.clientWidth) * 2 - 1; mouse.y = -(event.clientY / rendererDom.clientHeight) * 2 + 1; // ... 后续处理 }); // 监听鼠标点击事件 rendererDom.addEventListener('click', (event) => { // ... 后续处理 });

6.4.2 射线投射 (Raycasting)

射线投射是实现 3D 交互的核心技术。它模拟从相机发射一条射线,检测该射线与场景中物体的相交情况。通过射线投射,我们可以确定用户点击或悬停的对象。

  • Camera (相机): 射线投射的起点。

  • Raycaster (射线器): 用于创建和管理射线。

  • Scene Objects (场景物体): 场景中所有可能被射线击中的物体。

  • Intersection Points (交点): 射线与物体相交的点。

  • Handle Interaction (处理交互): 根据交点信息执行相应的操作。

代码示例:

import * as THREE from 'three'; // 创建射线器 const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); // 假设 scene 已经创建 // 假设 camera 已经创建 function onMouseMove(event) { // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值均为 -1 到 1 mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; // 通过摄像机和鼠标位置更新射线 raycaster.setFromCamera(mouse, camera); // 计算物体和射线的焦点 const intersects = raycaster.intersectObjects(scene.children); if (intersects.length > 0) { // intersects 是一个数组,包含所有与射线相交的物体 // intersects[0] 是最近的相交物体 const intersectedObject = intersects[0].object; // 处理交互,例如改变颜色 intersectedObject.material.color.set(0xff0000); // 红色 } else { // 如果没有相交物体,恢复颜色 scene.children.forEach(child => { if (child.material) { child.material.color.set(0xffffff); // 白色 } }); } } window.addEventListener('mousemove', onMouseMove, false);

代码详解:

  1. 创建 Raycaster 和 Vector2: Raycaster 用于进行射线投射,Vector2 用于存储鼠标的标准化坐标。

  2. onMouseMove 函数:

    • 获取鼠标坐标: event.clientXevent.clientY 获取鼠标在浏览器窗口中的位置。然后,将其转换为 Three.js 使用的标准化设备坐标 (-1 到 1)。

    • 更新射线: raycaster.setFromCamera(mouse, camera) 使用相机和鼠标位置更新射线。

    • 计算交点: raycaster.intersectObjects(scene.children) 计算射线与场景中所有物体的交点。 scene.children 是一个包含场景中所有直接子对象的数组。

    • 处理交点: intersects 是一个数组,包含所有与射线相交的物体。 intersects[0] 是最近的相交物体。 我们获取相交的物体,并改变其颜色。

    • 恢复颜色: 如果射线没有击中任何物体,我们将所有物体的颜色恢复为白色。

  3. 事件监听: window.addEventListener('mousemove', onMouseMove, false) 监听鼠标移动事件,并调用 onMouseMove 函数。

6.4.3 对象选择

对象选择是指用户通过点击或拖拽等方式选中场景中的一个或多个对象。射线投射是实现对象选择的常用方法。

// 监听鼠标点击事件 rendererDom.addEventListener('click', (event) => { // 更新鼠标坐标 mouse.x = (event.clientX / rendererDom.clientWidth) * 2 - 1; mouse.y = -(event.clientY / rendererDom.clientHeight) * 2 + 1; // 更新射线 raycaster.setFromCamera(mouse, camera); // 获取相交物体 const intersects = raycaster.intersectObjects(scene.children); if (intersects.length > 0) { const selectedObject = intersects[0].object; // 处理选择事件 console.log('Selected object:', selectedObject); // 可以改变颜色,添加边框,显示信息等 } });

6.4.4 对象控制

对象控制允许用户通过鼠标或键盘操作场景中的对象,例如旋转、平移、缩放等。

1. OrbitControls:

Three.js 提供了 OrbitControls,这是一个非常常用的控制器,允许用户围绕目标点旋转、平移和缩放相机。

import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; // 创建控制器 const controls = new OrbitControls(camera, renderer.domElement); // 可选设置 controls.enableDamping = true; // 启用阻尼,使旋转更平滑 controls.dampingFactor = 0.05; controls.screenSpacePanning = false; controls.minDistance = 1; controls.maxDistance = 1000; // 在渲染循环中更新控制器 function animate() { requestAnimationFrame(animate); controls.update(); // 必须调用 update() renderer.render(scene, camera); } animate();

代码详解:

  • 导入 OrbitControls: import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; 导入 OrbitControls 模块。

  • 创建 OrbitControls: const controls = new OrbitControls(camera, renderer.domElement); 创建一个 OrbitControls 实例,传入相机和渲染器的 DOM 元素。

  • 设置: controls.enableDamping = true; 启用阻尼效果,使相机移动更加平滑。 controls.dampingFactor = 0.05; 设置阻尼系数。 controls.screenSpacePanning = false; 禁用屏幕空间平移。 controls.minDistance = 1; 设置相机到目标点的最小距离。 controls.maxDistance = 1000; 设置相机到目标点的最大距离。

  • 更新控制器: controls.update(); 在渲染循环中调用 controls.update() 更新控制器。 这是非常重要的一步,否则控制器将不会生效。

2. TransformControls:

TransformControls 允许用户直接操作场景中的对象,进行平移、旋转和缩放。

import { TransformControls } from 'three/examples/jsm/controls/TransformControls'; // 创建控制器 const transformControls = new TransformControls(camera, renderer.domElement); scene.add(transformControls); // 监听对象选择事件 rendererDom.addEventListener('click', (event) => { // ... 射线投射代码 if (intersects.length > 0) { const selectedObject = intersects[0].object; // 将 TransformControls 附加到选定对象 transformControls.attach(selectedObject); } }); // 监听键盘事件,切换控制模式 window.addEventListener('keydown', function (event) { switch (event.keyCode) { case 84: // T transformControls.setMode("translate"); break; case 82: // R transformControls.setMode("rotate"); break; case 83: // S transformControls.setMode("scale"); break; } }); // 在渲染循环中更新控制器 function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); } animate();

代码详解:

  • 导入 TransformControls: import { TransformControls } from 'three/examples/jsm/controls/TransformControls'; 导入 TransformControls 模块。

  • 创建 TransformControls: const transformControls = new TransformControls(camera, renderer.domElement); 创建一个 TransformControls 实例,传入相机和渲染器的 DOM 元素。 scene.add(transformControls); 将 TransformControls 添加到场景中。

  • 附加到对象: transformControls.attach(selectedObject); 将 TransformControls 附加到选定的对象上。

  • 切换控制模式: transformControls.setMode("translate"); transformControls.setMode("rotate"); transformControls.setMode("scale"); 分别设置控制模式为平移、旋转和缩放。

  • 键盘事件监听: window.addEventListener('keydown', function (event) { ... }); 监听键盘事件,允许用户通过按键切换控制模式。

6.4.5 交互优化

  • 性能优化: 避免在渲染循环中进行复杂的计算。尽量缓存计算结果,并只在必要时更新。

  • 事件节流: 对于频繁触发的事件(例如鼠标移动),可以使用节流函数来限制事件处理的频率。

  • 空间划分: 对于大型场景,可以使用空间划分技术(例如八叉树)来加速射线投射的计算。

6.4.6 总结

Three.js 提供了强大的交互功能,通过事件监听、射线投射和各种控制器,我们可以创建丰富的互动体验。理解这些技术,并根据实际需求进行灵活应用,可以显著提升 3D 应用的吸引力和实用性。 通过本节的学习,你应该能够:

  • 理解 Three.js 中交互的基本原理。

  • 使用射线投射实现对象选择。

  • 使用 OrbitControlsTransformControls 控制相机和对象。

  • 了解交互优化的常用方法。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U