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

如何在React Three Fiber中实现GLB模型拆分为部件并缩放定位功能

React Three Fiber 实现 GLB 模型部件拆分与缩放定位方案

要实现类似 Autodesk Forge 的模型拆分、选中定位功能,核心分为两个核心模块:解析 GLB 模型提取所有独立部件并存储初始状态,分别实现爆炸拆分逻辑和部件选中后的相机适配逻辑。

前置依赖

你需要提前安装对应工具库:

  • @react-three/fiber:Three.js 的 React 封装核心库
  • @react-three/drei:常用 R3F 工具组件库,包含轨道控制器、GLB 加载等封装能力
  • @react-three/gltfjsx(可选):可以将 GLB 模型一键生成对应 React 组件,方便自定义每个部件的属性

步骤1:GLB 模型加载与部件信息提取

加载 GLB 时递归遍历所有子节点,筛选出所有 Mesh 类型的节点,存储每个部件的初始位置、包围盒信息,方便后续计算:

import { useGLTF, OrbitControls } from '@react-three/drei'
import { useRef, useState, useMemo } from 'react'
import * as THREE from 'three'

const ModelViewer = () => {
  const gltf = useGLTF('/你的模型路径/model.glb')
  const partsRef = useRef([]) // 存储所有部件的引用
  const controlsRef = useRef() // 轨道控制器引用
  const [explodeFactor, setExplodeFactor] = useState(0) // 拆分系数,0为原始状态,数值越大拆分距离越远
  // 计算整个模型的中心点,作为拆分的基准原点
  const modelCenter = useMemo(() => {
    const box = new THREE.Box3().setFromObject(gltf.scene)
    const center = new THREE.Vector3()
    box.getCenter(center)
    return center
  }, [gltf])

  // 遍历模型提取所有Mesh部件
  useMemo(() => {
    partsRef.current = []
    gltf.scene.traverse((child) => {
      if (child.isMesh) {
        // 存储每个部件的初始位置、原始包围盒
        child.userData.initialPosition = child.position.clone()
        child.userData.boundingBox = new THREE.Box3().setFromObject(child)
        partsRef.current.push(child)
      }
    })
  }, [gltf])

步骤2:实现模型拆分(爆炸)效果

原理是每个部件沿着「模型中心到自身中心」的方向,按照拆分系数偏移位置,系数为 0 时回到原始位置:

// 监听拆分系数变化,更新所有部件位置
  useMemo(() => {
    partsRef.current.forEach(part => {
      const partCenter = new THREE.Vector3()
      part.userData.boundingBox.getCenter(partCenter)
      // 计算从模型中心指向部件中心的方向向量
      const direction = partCenter.clone().sub(modelCenter).normalize()
      // 按照拆分系数偏移部件位置,0.1是拆分幅度系数,可根据模型大小自行调整
      const offset = direction.multiplyScalar(explodeFactor * 0.1)
      part.position.copy(part.userData.initialPosition.clone().add(offset))
    })
  }, [explodeFactor, modelCenter])

步骤3:实现部件选中缩放定位

给每个 Mesh 绑定点击事件,点击时计算部件的包围盒,调用控制器的 fitToBounds 方法自动适配相机位置,实现缩放定位:

const handlePartClick = (part, e) => {
    e.stopPropagation()
    // 适配相机到选中部件的包围盒,第二个参数控制是否开启动画过渡
    controlsRef.current.fitToBounds(part.userData.boundingBox, true)
    // 如果需要高亮选中部件,可在这里修改材质属性或者添加外轮廓效果
  }

  return (
    <>
      <OrbitControls ref={controlsRef} />
      <primitive 
        object={gltf.scene} 
        onClick={(e) => handlePartClick(e.object, e)}
      />
      {/* 拆分控制滑块示例,可自行替换为UI组件 */}
      <div style={{ position: 'absolute', top: 20, left: 20, background: '#fff', padding: '10px' }}>
        <label>模型拆分程度:</label>
        <input 
          type="range" 
          min="0" 
          max="10" 
          value={explodeFactor} 
          onChange={(e) => setExplodeFactor(Number(e.target.value))} 
        />
      </div>
    </>
  )
}

注意事项

  • 导出 GLB 模型时需要确保每个独立部件都是单独的 Mesh 节点,不要合并不必要的几何体,否则无法拆分出单个部件
  • 如果部件存在嵌套分组,遍历的时候要确保所有层级的 Mesh 都被提取到,不要只遍历第一层子节点
  • 拆分幅度系数可以根据自己的模型尺寸调整,避免拆分后部件偏移过远或者偏移不足
  • 如果需要选中部件时同步高亮,可直接修改对应 Mesh 的材质属性,也可以搭配 drei 的 Outline 组件实现外轮廓高亮效果,交互体验更好

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 09:45:04