【Three.js + R3F】全面掌握 useHelper:让调试可视化
在调试 3D 场景时,很多人会遇到这样的痛点:
-
光照打得太暗或太亮,看不出方向;
-
相机视锥、包围盒、平面等边界不可见;
-
不确定当前物体或阴影的范围是否正确。
而在 React Three Fiber(R3F)中,这些问题都可以通过一个极其实用的 Hook 来解决 —— useHelper。
一、useHelper 是什么?
useHelper 是 @react-three/drei 提供的一个调试辅助 Hook,
用于在场景中可视化相机、光源、坐标轴、包围盒等对象的辅助线。
它的本质是对 Three.js 中各类 THREE.*Helper 对象的封装,
在 React 环境中声明式使用,自动挂载、自动清理。
例如,在原生 Three.js 中:
scene.add(new THREE.CameraHelper(camera))而在 R3F 中,只需要一句:
useHelper(cameraRef, CameraHelper)二、基本语法
useHelper(ref, HelperClass, ...args)| 参数 | 说明 |
|---|---|
ref | 指向要可视化的对象(相机、光源、Mesh 等) |
HelperClass | Three.js 内置的 Helper 类,例如 CameraHelper |
...args | 其他可选参数(颜色、尺寸等) |
三、常见 Helper 类型
| 类型 | 对应 Helper | 示例用法 |
|---|---|---|
| 相机 | CameraHelper | useHelper(ref, CameraHelper, 'cyan') |
| 平行光 | DirectionalLightHelper | useHelper(ref, DirectionalLightHelper, 5, 'yellow') |
| 聚光灯 | SpotLightHelper | useHelper(ref, SpotLightHelper, 'red') |
| 点光源 | PointLightHelper | useHelper(ref, PointLightHelper, 1) |
| 半球光 | HemisphereLightHelper | useHelper(ref, HemisphereLightHelper, 2) |
| 平面 | PlaneHelper | useHelper(plane, PlaneHelper, 5, '#00ff00') |
| 包围盒 | BoxHelper | useHelper(meshRef, BoxHelper, 'blue') |
| 矩形光源 | RectAreaLightHelper | useHelper(ref, RectAreaLightHelper) |
| 坐标轴 | <axesHelper args={[size]} /> | 直接 JSX 使用 |
| 网格 | <gridHelper args={[size, divisions]} /> | 直接 JSX 使用 |
| 极坐标网格 | <polarGridHelper args={[radius, radials]} /> | JSX 使用 |
四、最佳实践
- 仅在开发调试阶段使用
这些辅助对象会增加渲染负担,不建议在正式环境启用。 - 组合使用多种 Helper
例如:
useHelper(dirLightRef, DirectionalLightHelper, 5, 'yellow')
useHelper(dirLightRef.current?.shadow?.camera, CameraHelper)→ 同时展示光照方向与阴影相机的可视范围。
五、独立型 Helper 与依附型 Helper 的区别
| 类型 | 示例 | 使用方式 |
|---|---|---|
| 依附型 Helper | 相机、光源、包围盒等 | 必须传入 ref:useHelper(ref, Helper) |
| 独立型 Helper | 坐标轴、网格、极坐标网格 | 直接 JSX:<axesHelper />、<gridHelper /> |
六、完整示例:覆盖所有常见 Helper
以下示例包含:
-
相机(透视、正交)
-
各类光源与阴影
-
坐标轴、网格、极坐标网格
-
BoxHelper、PlaneHelper、RectAreaLightHelper

import { Canvas, useFrame } from "@react-three/fiber";
import * as THREE from "three";
import {
PerspectiveCamera,
OrthographicCamera,
CameraControls,
useHelper,
} from "@react-three/drei";
import React, { useRef, useMemo } from "react";
import { RectAreaLightHelper } from "three/examples/jsm/helpers/RectAreaLightHelper.js";
const HelpersScene = () => {
// 为了从 THREE 解构需要的 Helper 类
const {
CameraHelper,
DirectionalLightHelper,
SpotLightHelper,
PointLightHelper,
HemisphereLightHelper,
BoxHelper,
Plane,
PlaneHelper,
Color,
Vector3,
} = THREE;
// === 相机 ===
const perspRef = useRef();
const orthoRef = useRef();
useHelper(perspRef, CameraHelper, "cyan"); // 透视相机 helper
useHelper(orthoRef, CameraHelper, "orange"); // 正交相机 helper
// === 光源 ===
const dirRef = useRef();
const spotRef = useRef();
const pointRef = useRef();
const hemiRef = useRef();
const rectRef = useRef();
useHelper(dirRef, DirectionalLightHelper, 3, "yellow"); // 显示平行光方向与光锥,第三个参数为 helper 大小(长度)与颜色
useHelper(spotRef, SpotLightHelper, "red"); // 显示聚光灯的方向与角度(颜色可选,用于观察光锥范围)
useHelper(pointRef, PointLightHelper, 0.6, "white"); // 显示点光源位置与可视半径(尺寸、颜色可选)
useHelper(hemiRef, HemisphereLightHelper, 1.5); // 显示半球光的上下颜色对比与可视尺寸
useHelper(rectRef, RectAreaLightHelper); // 显示矩形区域光的方向和形状(无颜色参数,主要用于调试方向)
// === BoxHelper (包围盒) ===
const boxTarget = useRef();
useHelper(boxTarget, BoxHelper, new Color("#38bdf8"));
// === PlaneHelper(几何平面可视化)===
// 注意:PlaneHelper 需要的是“平面对象”本身,而不是 ref。
const plane = useMemo(() => new Plane(new Vector3(0, 1, 0), 0), []);
useHelper(plane, PlaneHelper, 5, "#10b981"); // 关键修正点
// 动一动盒子,方便观察 BoxHelper 变化
useFrame(({ clock }) => {
const t = clock.getElapsedTime();
if (boxTarget.current) {
boxTarget.current.rotation.y = t * 0.5;
boxTarget.current.position.x = Math.sin(t) * 1.2;
}
});
return (
<>
{/* 透视相机(主相机) */}
<PerspectiveCamera
ref={perspRef}
makeDefault
position={[6, 4, 10]}
fov={55}
near={0.1}
far={200}
/>
{/* 正交相机(展示 helper,不作为默认相机) */}
<OrthographicCamera ref={orthoRef} position={[-8, 6, 10]} zoom={50} />
{/* 控制器 */}
<CameraControls dollySpeed={0.3} truckSpeed={0.6} />
{/* 灯光们 */}
<hemisphereLight ref={hemiRef} position={[0, 6, 0]} intensity={0.4} />
<directionalLight
ref={dirRef}
position={[6, 10, 6]}
intensity={1.2}
castShadow
/>
<spotLight
ref={spotRef}
position={[-6, 8, 2]}
angle={0.4}
penumbra={0.3}
intensity={1.2}
castShadow
/>
<pointLight ref={pointRef} position={[0, 3, -6]} intensity={1.2} />
{/* RectAreaLight(这里只演示 helper,可见光照需配合 physicallyCorrectLights 等) */}
<rectAreaLight
ref={rectRef}
position={[0, 5, 6]}
width={2.5}
height={1.2}
intensity={5}
lookAt={[0, 0, 0]}
/>
{/* ====== 这些“独立型” Helper 用 JSX 组件而不是 useHelper ====== */}
{/* 坐标轴 */}
<axesHelper args={[3]} />
{/* 网格(size, divisions, color1, color2) */}
<gridHelper args={[20, 20]} position={[0, -1.5, 0]} />
{/* 极坐标网格(radius, radials, circles, divisions, color1, color2) */}
<polarGridHelper args={[10, 16]} position={[0, -1.49, 0]} />
{/* 地面 */}
<mesh rotation-x={-Math.PI / 2} position={[0, -1.5, 0]} receiveShadow>
<planeGeometry args={[100, 100]} />
<meshStandardMaterial color="#0f172a" roughness={0.9} metalness={0.1} />
</mesh>
{/* 用于 BoxHelper 的目标物体 */}
<group position={[0, 0, 0]} ref={boxTarget}>
<mesh castShadow receiveShadow>
<boxGeometry args={[1.2, 1.2, 1.2]} />
<meshStandardMaterial
color="#38bdf8"
metalness={0.3}
roughness={0.4}
/>
</mesh>
<mesh position={[0, 1.1, 0]} castShadow>
<sphereGeometry args={[0.45, 32, 32]} />
<meshStandardMaterial
color="#a78bfa"
metalness={0.2}
roughness={0.5}
/>
</mesh>
</group>
{/* 一些参考物体 */}
<mesh
position={[3, -0.5, -2]}
rotation-y={Math.PI / 6}
castShadow
receiveShadow
>
<cylinderGeometry args={[0.5, 0.5, 2, 32]} />
<meshStandardMaterial color="#10b981" />
</mesh>
<mesh
position={[-3, -1.0, 2]}
castShadow
receiveShadow
rotation-x={-Math.PI / 12}
>
<torusKnotGeometry args={[0.5, 0.18, 120, 16]} />
<meshStandardMaterial
color="#f59e0b"
metalness={0.4}
roughness={0.35}
/>
</mesh>
</>
);
};
const Helper = () => {
return (
<Canvas
shadows
dpr={[1, 2]}
gl={{ antialias: true }}
camera={{ position: [6, 4, 10], fov: 55 }}
>
<color attach="background" args={["#0b1120"]} />
<HelpersScene />
</Canvas>
);
};
export default Helper;七、运行效果与总结
运行后,你会看到完整的调试辅助线:
-
蓝/橙线框:相机视锥体(透视 + 正交)
-
黄/红/白灯光辅助箭头:表示光照方向与角度
-
绿色平面:PlaneHelper 显示的几何平面
-
蓝色包围框:BoxHelper 动态跟随旋转物体
-
坐标轴 + 网格:提供场景参考系
这些可视化线框能帮助开发者:
-
确认相机和光照是否正确;
-
调整阴影范围;
-
验证几何体与包围盒的精度;
-
快速定位场景问题。
八、总结要点
| 内容 | 说明 |
|---|---|
| 主要用途 | 可视化调试相机、光源、平面、包围盒等 |
| 导入方式 | import { useHelper } from "@react-three/drei" |
| 使用方式 | useHelper(ref, HelperClass, ...args) |
| 特殊情况 | 坐标/网格类用 JSX;PlaneHelper 直接传 Plane 对象 |
| 建议 | 开发调试启用,生产关闭 |
🧭 结语
useHelper是 Three.js 调试阶段最有价值的工具之一。
它不参与渲染逻辑,却能让你“看清”场景内部的结构与光照逻辑。
在构建复杂的可视化项目时,它几乎是必备的开发助手。
是否希望我在文章末尾帮你补一段「公众号摘要 + 封面图文建议」?
可以用于微信后台发布时的封面摘要和推荐语。