You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

react-three-fiber:如何捕获<Canvas />内任意位置的事件?

解决方案

要实现Canvas任意位置的交互(包括物体和空白区域),可以在<Canvas>内部创建一个全局事件监听组件,直接利用useThree获取Three.js上下文并手动进行射线检测,具体步骤如下:

1. 创建全局鼠标监听组件

在<Canvas>内部添加一个独立的组件(不要用<Html>包裹3D对象),用于监听Canvas的鼠标事件并处理射线检测:

import { useThree, useEffect } from '@react-three/fiber';
import * as THREE from 'three';

export function GlobalMouseListener() {
  const { raycaster, camera, gl, scene } = useThree();

  useEffect(() => {
    const handleMouseDown = (event) => {
      // 将鼠标坐标转换为Three.js标准化设备坐标(NDC)
      const mouse = new THREE.Vector2();
      mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
      mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

      // 更新射线投射器的起点和方向
      raycaster.setFromCamera(mouse, camera);

      // 检测与场景中所有物体的相交(true表示递归检测子物体)
      const intersects = raycaster.intersectObjects(scene.children, true);

      if (intersects.length > 0) {
        // 场景(a):点击到物体
        console.log('点击到物体', intersects[0].object);
        // 可获取相交点世界坐标:intersects[0].point
      } else {
        // 场景(b):点击空白区域
        console.log('点击空白区域');
        // 如需获取空白区域对应的世界坐标,可从射线上取点:
        // const worldPoint = new THREE.Vector3();
        // raycaster.ray.at(10, worldPoint); // 取射线上10单位处的点
      }
    };

    const canvas = gl.domElement;
    canvas.addEventListener('mousedown', handleMouseDown);

    // 组件卸载时移除事件监听
    return () => {
      canvas.removeEventListener('mousedown', handleMouseDown);
    };
  }, [raycaster, camera, gl, scene]);

  // 该组件无需渲染可视内容
  return null;
}

2. 在Canvas中使用该组件

将GlobalMouseListener与其他3D组件放在同一层级,不要用它包裹mesh等Three.js对象:

import { Canvas } from '@react-three/fiber';

function App() {
  return (
    <Canvas>
      <GlobalMouseListener />
      {/* 你的3D物体 */}
      <mesh>
        <boxGeometry />
        <meshBasicMaterial color="red" />
      </mesh>
    </Canvas>
  );
}

关键说明

  • 规避<Html>组件的误用:<Html>是用于在Canvas上层渲染DOM元素的,不能嵌套mesh等3D对象,这也是你之前报错的核心原因。
  • 手动射线检测:通过raycaster.intersectObjects主动检测所有物体,既可以捕获物体点击事件,也能通过返回结果为空判断空白区域的点击。
  • 绑定Canvas原生事件:直接获取渲染器的DOM元素(gl.domElement)绑定事件,确保能覆盖整个Canvas区域的交互。

内容的提问来源于stack exchange,提问作者Anson Kao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 07:41:30