
关于
Three.js 交互 - 射线检测、控制器、鼠标/触摸输入、物体选择。适用于处理用户输入、实现点击检测、添加相机控制或创建交互式 3D 体验。
name: threejs-interaction description: Three.js交互 - 射线投射、控制器、鼠标/触摸输入、对象选择。用于处理用户输入、实现点击检测、添加相机控制或创建交互式3D体验。 risk: unknown source: community
Three.js交互
使用场景
- 你需要在Three.js场景中实现用户交互。
- 任务涉及射线投射、对象拾取、指针处理、触摸输入或相机控制。
- 你正在构建交互式3D体验而非被动渲染。
快速开始
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
// Camera controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
// Raycasting for click detection
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
function onClick(event) {
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) {
console.log("Clicked:", intersects[0].object);
}
}
window.addEventListener("click", onClick);
射线投射器
基础射线投射
const raycaster = new THREE.Raycaster();
// From camera (mouse picking)
raycaster.setFromCamera(mousePosition, camera);
// From any origin and direction
raycaster.set(origin, direction); // origin: Vector3, direction: normalized Vector3
// Get intersections
const intersects = raycaster.intersectObjects(objects, recursive);
// intersects array contains:
// {
// distance: number, // Distance from ray origin
// point: Vector3, // Intersection point in world coords
// face: Face3, // Intersected face
// faceIndex: number, // Face index
// object: Object3D, // Intersected object
// uv: Vector2, // UV coordinates at intersection
// uv1: Vector2, // Second UV channel
// normal: Vector3, // Interpolated face normal
// instanceId: number // For InstancedMesh
// }
鼠标位置转换
const mouse = new THREE.Vector2();
function updateMouse(event) {
// For full window
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
// For specific canvas element
function updateMouseCanvas(event, canvas) {
const rect = canvas.getBoundingClientRect();
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
}
触摸支持
function onTouchStart(event) {
event.preventDefault();
if (event.touches.length === 1) {
const touch = event.touches[0];
mouse.x = (touch.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(touch.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(clickableObjects);
if (intersects.length > 0) {
handleSelection(intersects[0]);
}
}
}
renderer.domElement.addEventListener("touchstart", onTouchStart);
射线投射器选项
const raycaster = new THREE.Raycaster();
// Near/far clipping (default: 0, Infinity)
raycaster.near = 0;
raycaster.far = 100;
// Line/Points precision
raycaster.params.Line.threshold = 0.1;
raycaster.params.Points.threshold = 0.1;
// Layers (only intersect objects on specific layers)
raycaster.layers.set(1);
高效射线投射
// Only check specific objects
const clickables = [mesh1, mesh2, mesh3];
const intersects = raycaster.intersectObjects(clickables, false);
// Use layers for filtering
mesh1.layers.set(1); // Clickable layer
raycaster.layers.set(1);
// Throttle raycast for hover effects
let lastRaycast = 0;
function onMouseMove(event) {
const now = Date.now();
if (now - lastRaycast < 50) return; // 20fps max
lastRaycast = now;
// Raycast here
}
相机控制
OrbitControls
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
const controls = new OrbitControls(camera, renderer.domElement);
// Damping (smooth movement)
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Rotation limits
controls.minPolarAngle = 0; // Top
controls.maxPolarAngle = Math.PI / 2; // Horizon
controls.minAzimuthAngle = -Math.PI / 4; // Left
controls.maxAzimuthAngle = Math.PI / 4; // Right
// Zoom limits
controls.minDistance = 2;
controls.maxDistance = 50;
// Enable/disable features
controls.enableRotate = true;
controls.enableZoom = true;
controls.enablePan = true;
// Auto-rotate
controls.autoRotate = true;
controls.autoRotateSpeed = 2.0;
// Target (orbit point)
controls.target.set(0, 1, 0);
// Update in animation loop
function animate() {
controls.update(); // Required when damping is enabled
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
兼容工具
Claude CodeCursor
标签
前端开发