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

React-Three-Fiber加载Rhino3dm模型后网格鼠标事件失效的解决方法

问题:Rhino3dm模型在react-three-fiber中鼠标悬停事件失效

在react-three-fiber中加载Rhino3dm格式模型时,尝试为每个网格部件添加鼠标悬停变色功能,但鼠标事件无法正常触发。此前加载GLTF模型时,通过Object.values(gltf.nodes).map并过滤isMesh对象的方式可以正常工作,但改用object.children.map处理Rhino3dm模型时事件异常。

原因分析

  • 非Mesh对象混入:Rhino3dmLoader加载返回的object.children中包含非Mesh类型的对象(比如Group容器),这些对象没有几何体,无法触发射线检测事件。而GLTF处理时手动过滤了isMesh的对象,避免了这个问题。
  • 组件嵌套错误:外层用<mesh>包裹<primitive object={child}>会导致嵌套冲突——如果child本身已经是Mesh,这种嵌套会让射线检测逻辑混乱,无法正确触发事件。
  • 材质未正确绑定:直接创建新材质并传递给<primitive>无法正确覆盖原对象的材质,且未用useMemo缓存材质会导致不必要的重渲染,影响事件响应。

解决方法

步骤1:过滤Mesh对象

遍历Rhino3dm模型的children时,只保留isMesh为true的对象,确保只处理可交互的网格部件。

步骤2:正确绑定事件与材质

直接对Mesh对象添加事件监听,通过useMemo缓存材质避免重渲染,替换原对象的材质而非嵌套组件。

修改后的完整代码

import "./styles.css";
import * as THREE from "three";
import { useMemo, useState } from "react";
import { Canvas, useLoader } from "@react-three/fiber";
import { Rhino3dmLoader } from "three/examples/jsm/loaders/3DMLoader";
import { Environment, OrbitControls } from "@react-three/drei";
import { Suspense } from "react";

const Part = ({ mesh }) => {
  const [hovered, setHover] = useState(false);
  // 用useMemo缓存材质,避免重渲染
  const material = useMemo(() => 
    new THREE.MeshStandardMaterial({
      color: hovered ? "hotpink" : "orange"
    }), 
    [hovered]
  );

  return (
    <primitive
      key={mesh.id}
      object={mesh}
      material={material}
      castShadow
      receiveShadow
      onPointerOver={(e) => {
        e.stopPropagation();
        setHover(true);
      }}
      onPointerOut={(e) => {
        e.stopPropagation();
        setHover(false);
      }}
    />
  );
};

const Model = () => {
  const object = useLoader(Rhino3dmLoader, "./rhino_logo.3dm", (loader) => {
    loader.setLibraryPath("https://cdn.jsdelivr.net/npm/rhino3dm@0.15.0-beta/");
  });

  // 只过滤出Mesh类型的子对象
  const model = object.children
    .filter(child => child.isMesh)
    .map(mesh => <Part key={mesh.id} mesh={mesh} />);

  return model;
};

export default function App() {
  return (
    <div className="App">
      <Canvas>
        <Suspense fallback={null}>
          <Model />
          <OrbitControls />
          <Environment preset="sunset" background />
        </Suspense>
      </Canvas>
    </div>
  );
}

关键修改点说明

  • 新增filter(child => child.isMesh):只处理可交互的网格元素,排除Group等容器对象。
  • 移除外层<mesh>:直接使用<primitive>绑定原Mesh对象,避免组件嵌套导致的射线检测问题。
  • useMemo缓存材质:减少不必要的材质重建,提升性能同时保证事件响应稳定。
  • 调整Part组件接收参数:明确传递mesh对象,避免props解构错误。

内容的提问来源于stack exchange,提问作者4kk11

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 08:56:06