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

如何使用Drei的CameraControls启用平移并禁用缩放与旋转

解决Drei CameraControls无法禁用缩放/旋转的问题

你的问题出在监听controlsRef的useEffect不会触发——因为React ref本身是稳定引用,仅current属性变化不会触发依赖controlsRef的useEffect执行,而组件挂载时controlsRef.current可能还未初始化完成,导致属性设置失效。

下面提供两种可靠解决方案:

方案一:利用useThree返回的controls实例

当给<CameraControls>设置makeDefault后,useThree()返回的controls会直接指向CameraControls实例,监听这个controls即可确保属性设置时机正确:

function Rig({ position = new THREE.Vector3(0, 0, 2), focus = new THREE.Vector3(0, 0, 0) }) {
  const { controls, scene } = useThree()
  const [, params] = useRoute('/item/:id')

  useEffect(() => {
    const active = scene.getObjectByName(params?.id)
    if (active) {
      active.parent.localToWorld(position.set(0, 0.5, 0.25))
      active.parent.localToWorld(focus.set(0, 0, 5))
    }
    controls?.setLookAt(...position.toArray(), ...focus.toArray(), true)
  }, [controls, scene, params?.id, focus, position])

  useEffect(() => {
    if (controls) {
      // 禁用缩放和旋转,保留平移
      controls.enableZoom = false
      controls.enablePan = true
      controls.enableRotate = false
      controls.update()
    }
  }, [controls]) // 依赖改为controls,确保实例就绪后执行

  return <CameraControls makeDefault minPolarAngle={0} maxPolarAngle={Math.PI * 2} />
}

方案二:使用CameraControls的onReady回调

Drei的CameraControls提供onReady属性,会在控件完全初始化后触发,直接在这里配置属性:

function Rig({ position = new THREE.Vector3(0, 0, 2), focus = new THREE.Vector3(0, 0, 0) }) {
  const { scene } = useThree()
  const [, params] = useRoute('/item/:id')
  const controlsRef = useRef()

  useEffect(() => {
    const active = scene.getObjectByName(params?.id)
    if (active) {
      active.parent.localToWorld(position.set(0, 0.5, 0.25))
      active.parent.localToWorld(focus.set(0, 0, 5))
    }
    controlsRef.current?.setLookAt(...position.toArray(), ...focus.toArray(), true)
  }, [scene, params?.id, focus, position])

  const handleControlsReady = (cameraControls) => {
    // 禁用缩放和旋转,保留平移
    cameraControls.enableZoom = false
    cameraControls.enablePan = true
    cameraControls.enableRotate = false
    cameraControls.update()
    controlsRef.current = cameraControls
  }

  return (
    <CameraControls 
      ref={controlsRef}
      makeDefault 
      minPolarAngle={0} 
      maxPolarAngle={Math.PI * 2}
      onReady={handleControlsReady}
    />
  )
}

两种方案都能确保在CameraControls实例就绪后修改属性,避免时机问题导致的设置失效,同时保留你需要的镜头过渡效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 10:53:31