如何使用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
相关产品推荐
相关产品推荐

