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

如何使用Orthographic Camera在Three.js场景内自由移动?

OrthographicCamera 配合 CameraControls 实现自由移动(进入模型内部+缩放视图)

问题描述

我使用React Three Drei的CameraControls,需要实现场景内自由移动:场景中有一个立方体,既能缩小视图查看全貌,也能移动到立方体内部向外看(仅显示单个面)。

使用PerspectiveCamera时该需求轻松实现,示例代码如下:

import { CameraControls } from "@react-three/drei";
const cameraControlsRef = useRef<CameraControls | null>(null);

function zoom(){
  cameraControlsRef.current.truck(camera.zoom / 2, 0, true);
}

但切换到OrthographicCamera后无法达到预期效果:调用dolly方法无任何反应,调用zoom方法仅能实现视图缩放,相机位置保持不变,无法进入立方体内部。相关代码:

function zoom(){
  cameraControlsRef.current.zoom(camera.zoom / 2, true);
}

完整示例代码:

import { Canvas } from "@react-three/fiber";
import { generateCubePoints } from "./generateCubePoints";
import {
  CameraControls,
  OrthographicCamera,
  PerspectiveCamera,
  Edges,
} from "@react-three/drei";

export const ITEMS_PER_ROW = 3;

function App() {
  return (
    <div style={{ height: "100vh", width: "100vw", background: "blue" }}>
      <Canvas>
        {/* <PerspectiveCamera
          position={[150, 150, 150]}
          makeDefault
          far={10000}
          near={0.1}
        /> */}
        <OrthographicCamera makeDefault position={[150, 150, 150]} />
        <CameraControls />
        <ambientLight intensity={0.1} />
        <directionalLight color="red" position={[0, 0, 5]} />
        <mesh>
          <boxGeometry args={[100, 100, 100]} />
          <meshStandardMaterial opacity={0.5} />
          <Edges />
        </mesh>
      </Canvas>
    </div>
  );
}

export default App;

问题根源

OrthographicCamera与PerspectiveCamera的缩放逻辑存在本质差异:

  • PerspectiveCamera通过**改变相机位置(前后移动)**配合FOV调整实现视觉缩放效果;
  • OrthographicCamera的缩放仅修改zoom属性,本质是调整视锥体尺寸,相机位置不会发生变化——这就是调用zoom方法无法进入立方体内部的原因。

解决方法

要实现进入立方体内部的效果,需要结合相机位置移动与zoom值调整,而不是仅依赖zoom方法。以下是修改后的实现:

import { useRef, useEffect } from "react";
import { Canvas, useThree } from "@react-three/fiber";
import {
  CameraControls,
  OrthographicCamera,
  Edges,
} from "@react-three/drei";

function App() {
  return (
    <div style={{ height: "100vh", width: "100vw", background: "blue" }}>
      <Canvas>
        <OrthographicCamera makeDefault position={[150, 150, 150]} near={0.1} far={10000} />
        <CameraControlsWrapper />
        <ambientLight intensity={0.1} />
        <directionalLight color="red" position={[0, 0, 5]} />
        <mesh>
          <boxGeometry args={[100, 100, 100]} />
          <meshStandardMaterial opacity={0.5} />
          <Edges />
        </mesh>
      </Canvas>
    </div>
  );
}

function CameraControlsWrapper() {
  const cameraControlsRef = useRef<CameraControls | null>(null);
  const { camera } = useThree();

  // 自定义缩放+移动逻辑
  const handleZoomAndMove = () => {
    if (!cameraControlsRef.current) return;
    
    // 平滑向立方体中心移动相机
    const target = [0, 0, 0]; // 立方体中心坐标
    const newPos = camera.position.map((pos, idx) => pos + (target[idx] - pos) * 0.3);
    cameraControlsRef.current.setPosition(...newPos, true);
    
    // 同步调整zoom值,优化视觉效果
    camera.zoom *= 0.7;
    camera.updateProjectionMatrix();
  };

  // 绑定键盘事件(按Z键触发)
  useEffect(() => {
    const onKeyDown = (e: KeyboardEvent) => {
      if (e.key === "z") handleZoomAndMove();
    };
    window.addEventListener("keydown", onKeyDown);
    return () => window.removeEventListener("keydown", onKeyDown);
  }, []);

  return <CameraControls ref={cameraControlsRef} />;
}

export default App;

额外提示

  • 若要让CameraControls的默认鼠标滚轮交互实现相同效果,可监听滚轮事件,替换默认的zoom行为为“移动相机+调整zoom”;
  • 务必设置合适的near和far属性,避免相机移动时超出视锥体范围导致模型消失;
  • 使用setPosition的第三个参数true开启平滑过渡,提升交互体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 09:22:33