
React Three Fiber 如何用 useFrame 的 renderPriority 接管渲染循环【免费下载链接】react-three-fiber A React renderer for Three.js项目地址: https://gitcode.com/GitHub_Trending/re/react-three-fiber当你要在主场景之上叠加一个抬头显示HUD、按指定顺序渲染多个场景、或者自行掌控整条渲染管线例如搭配 effect composer时React Three FiberR3F默认的每帧自动渲染一次默认场景就不够了。官方给出的做法是给useFrame传入一个正数renderPriority一旦存在这样的订阅者R3F 会完全禁用自动渲染渲染的责任转移到你自己的回调里各回调按优先级升序执行。本文基于仓库中的 hooks 文档、渲染循环源码 和 Viewcube 示例 说明如何完成这次接管。默认行为为什么需要接管按 how-it-works 的说明Fiber 默认会建立一条渲染循环把默认的scene从默认的camera渲染到 WebGLRendererCanvas 的frameloop属性默认值为always。useFrame的回调会在每一帧渲染之前被调用回调接收state与useThree相同包含gl、scene、camera等和以秒为单位的delta组件卸载时会从渲染循环中自动退订。也就是说默认情况下你只负责在渲染前改状态画什么、何时画由 R3F 决定——单场景、单相机、每帧一次gl.render(scene, camera)。hooks 文档明确列出了需要接管的典型场景effect composer、heads-up displays 等即你需要在一帧内多次调用gl.render并控制它们的先后顺序。准备安装依赖npm install three react-three/fiber注意 安装文档 中的版本配对要求react-three/fiber9对应react19react-three/fiber8对应react18。如果使用 Vite官方给出的路径是# Create app npm create vite my-app # Select react as framework # Install dependencies cd my-app npm install three react-three/fiber # Start development server npm run dev机制正数 renderPriority 会禁用自动渲染hooks 文档对接管渲染循环的原话是If you need more control you may pass a numericalrenderPriorityvalue. This will cause React Three Fiber to disable automatic rendering altogether. It will now be your responsibility to render.渲染循环源码印证了这一点loop.ts 中在所有useFrame订阅者执行完之后// Render content if (!state.internal.priority state.gl.render) state.gl.render(state.scene, state.camera)即只有当不存在正数优先级订阅者state.internal.priority为假值时R3F 才会替你渲染默认场景一旦你以正数优先级注册了useFrame这行自动渲染就会被跳过。关于执行顺序文档有一条明确的 NOTE回调按优先级值升序执行lowest first, highest last类似 DOM 的 z-order。文档示例function Render() { // Takes over the render-loop, the user has the responsibility to render useFrame(({ gl, scene, camera }) { gl.render(scene, camera) }, 1) } function RenderOnTop() { // This will execute *after* Renders useframe useFrame(({ gl, scene, camera }) { gl.render(scene, camera) }, 2) }也就是说优先级1的回调先跑2的回调后跑你可以用多个不同优先级把一帧里的多次渲染排成确定的序列。仓库实例用优先级 1 叠加一个 HUD 场景仓库示例 Viewcube.tsx 完整演示了接管渲染循环 叠加第二场景的写法。它创建了一个独立的THREE.Scene和正交相机通过createPortal把 viewcube 网关注入该场景然后useFrame(() { matrix.copy(defaultCamera.matrix).invert() ref.current.quaternion.setFromRotationMatrix(matrix) gl.autoClear true gl.render(defaultScene, defaultCamera) gl.autoClear false gl.clearDepth() gl.render(scene, camera) }, 1)这段代码的每步作用都能从代码本身读出先用默认场景、默认相机把主场景画出来gl.autoClear false并gl.clearDepth()保证第二次渲染不清除主场景的颜色缓冲viewcube 因此能叠在主场景之上第二个scene/camera是useMemo里单独创建的专门承载 HUD 内容。末尾的, 1是关键它使 R3F 的自动渲染失效以上所有gl.render都是你自己完成的。这个组件放在Canvas里即可随主场景一起工作示例入口见 example/src/demos/Viewcube.tsx同目录的 ViewTracking.tsx 则用多个递增的优先级index把多个场景分别渲染到画布的不同区域是同一机制的扩展用法。负数优先级只排序不接管如果你只是想调整多个useFrame在组件树中的执行顺序而不想接管渲染循环应使用负数索引。文档明确说明负数索引不会接管渲染循环function A() { // This will execute first useFrame(() { // ... }, -2) } function B() { // This useFrame will execute *after* As useFrame(() { // ... }, -1) }这里有一个版本相关的坑来自 fiber 的 CHANGELOGv7.0.0 之前负数索引存在一个边缘情况会意外禁用自动渲染Surprisingly this disabled auto-rendering although the documentation says positive numbers only。自 v7 起该行为被修复负数索引只用于排序、不再接管渲染循环。如果你的代码是从 v6 或更早迁移来的迁移时要以 v7 的语义为准。限制与注意事项Hooks 只能在Canvas内部使用因为它们依赖 context。在Canvas之外调用useFrame/useThree会直接报错hooks 文档开头的 NOTE。文档用 CAUTION 级别的提示警告不要在useFrame里setState回调计算要精简并留意循环类代码的常见陷阱。接管之后渲染完全由你负责正数优先级存在时 R3F 不再自动渲染见 loop.ts如果你注册了正数优先级却忘了调用gl.render画面将得不到更新。frameloopalways/demand/never是 Canvas 上另一套渲染模式配置默认always本文的接管路径与它相互独立按需另行查阅 canvas 文档。如何验证接管生效文档没有提供专用检查命令但可以从三个可观察的行为判断自动渲染已被跳过源码条件!state.internal.priority决定了只要有任何正数优先级的useFrame存在R3F 就不会再替你调用gl.render(state.scene, state.camera)。把接管组件移出场景树或注释掉画面恢复由 R3F 自动渲染即可反证接管确实生效。多次渲染按优先级排序按文档的说明优先级1的回调先于优先级2的回调执行。Viewcube 示例中主场景先画、HUD 后画并叠在上方正是这个顺序的可见结果。参考实现可运行仓库的 Viewcube 示例 是可直接对照的完整实现——主场景是一个 torus右上角出现一个随主相机旋转的 viewcube说明第二场景确实在主场景之后被独立渲染。完成接管后后续改动都集中在你正数优先级的回调里增加场景就增加一次gl.render调整层次就调整优先级数值。【免费下载链接】react-three-fiber A React renderer for Three.js项目地址: https://gitcode.com/GitHub_Trending/re/react-three-fiber创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考