useThree 详解
可获取的对象
import { useThree } from "@react-three/fiber";
function MyComponent() {
const {
camera, // ✅ 当前相机
scene, // Three.js 场景
gl, // WebGL 渲染器
size, // 画布尺寸 { width, height }
viewport, // 视口信息
raycaster, // 射线投射器
clock, // 时钟
mouse, // 鼠标坐标
// ... 更多
} = useThree();
return null;
}常用场景
// 1. 获取相机位置
const { camera } = useThree();
console.log(camera.position);
// 2. 获取画布尺寸
const { size } = useThree();
console.log(size.width, size.height);
// 3. 获取视口尺寸(3D 空间单位)
const { viewport } = useThree();
console.log(viewport.width, viewport.height);
// 4. 手动渲染
const { gl, scene, camera } = useThree();
gl.render(scene, camera);更推荐的写法(使用 useFrame)
import { useGLTF, useKeyboardControls } from "@react-three/drei";
import {
CapsuleCollider,
RigidBody,
RapierRigidBody,
} from "@react-three/rapier";
import { useRef, useMemo } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import { Vector3 } from "three";
import { toFixed } from "../../utils/math";
useGLTF.preload("/models/Actor/actor.gltf");
function Player() {
const SPEED = 4;
const JUMP = 7;
const { camera } = useThree();
const { scene } = useGLTF("/models/Actor/actor.gltf");
const player = useRef<RapierRigidBody>(null);
const [, getKeys] = useKeyboardControls();
// ✅ 使用 useMemo 避免每次渲染都创建新向量
const velocity = useMemo(() => new Vector3(), []);
// ✅ 推荐:在 useFrame 中处理移动逻辑
useFrame(() => {
if (!player.current) return;
const { forward, backward, left, right, jump } = getKeys();
// 计算移动方向
velocity
.set(
Number(right) - Number(left),
0,
Number(backward) - Number(forward)
)
.normalize()
.multiplyScalar(SPEED)
.applyEuler(camera.rotation); // ✅ 直接使用 camera
const currentVel = player.current.linvel();
player.current.setLinvel(
{
x: toFixed(velocity.x),
y: currentVel.y,
z: toFixed(velocity.z),
},
true
);
// 跳跃
if (jump && Math.abs(currentVel.y) < 0.1) {
player.current.setLinvel({ x: 0, y: JUMP, z: 0 }, true);
}
});
return (
<group dispose={null}>
<RigidBody
ref={player}
colliders={false}
type="dynamic"
enabledRotations={[false, false, false]}
position={[0, 4, 0]}
lockRotations
>
<primitive object={scene} />
<CapsuleCollider args={[0.6, 0.3]} />
</RigidBody>
</group>
);
}
export default Player;两种方案对比
useThree 的完整示例
import { useThree, useFrame } from "@react-three/fiber";
function CameraLogger() {
const { camera, size, viewport } = useThree();
useFrame(() => {
console.log('相机位置:', camera.position);
console.log('画布尺寸:', size.width, 'x', size.height);
console.log('视口尺寸:', viewport.width, 'x', viewport.height);
});
return null;
}总结
获取相机的方法:
import { useThree } from "@react-three/fiber";
const { camera } = useThree();最佳实践:
✅ 使用
useThree()获取 camera✅ 在
useFrame中处理移动逻辑(而不是useKeyboardControls回调)✅ 使用
useMemo优化向量创建
现在 camera 可以正常使用了!🎮