news 2026/9/10 22:11:15

React Three Fiber 如何用 useFrame 的 renderPriority 接管渲染循环?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
React Three Fiber 如何用 useFrame 的 renderPriority 接管渲染循环?

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 Fiber(R3F)默认的"每帧自动渲染一次默认场景"就不够了。官方给出的做法是给useFrame传入一个正数renderPriority:一旦存在这样的订阅者,R3F 会完全禁用自动渲染,渲染的责任转移到你自己的回调里,各回调按优先级升序执行。本文基于仓库中的 hooks 文档、渲染循环源码 和 Viewcube 示例 说明如何完成这次接管。

默认行为:为什么需要接管

按 how-it-works 的说明,Fiber 默认会建立一条渲染循环,把默认的scene从默认的camera渲染到 WebGLRenderer;Canvas 的frameloop属性默认值为always

useFrame的回调会在每一帧渲染之前被调用,回调接收state(与useThree相同,包含glscenecamera等)和以秒为单位的delta;组件卸载时会从渲染循环中自动退订。也就是说,默认情况下你只负责在渲染前改状态,"画什么、何时画"由 R3F 决定——单场景、单相机、每帧一次gl.render(scene, camera)

hooks 文档明确列出了需要接管的典型场景:effect composer、heads-up displays 等,即你需要在一帧内多次调用gl.render,并控制它们的先后顺序。

准备:安装依赖

npm install three @react-three/fiber

注意 安装文档 中的版本配对要求:@react-three/fiber@9对应react@19@react-three/fiber@8对应react@18。如果使用 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* Render's 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)

这段代码的每步作用都能从代码本身读出:

  1. 先用默认场景、默认相机把主场景画出来;
  2. gl.autoClear = falsegl.clearDepth(),保证第二次渲染不清除主场景的颜色缓冲,viewcube 因此能叠在主场景之上;
  3. 第二个scene/camerauseMemo里单独创建的,专门承载 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* A's useFrame(() => { // ... }, -1) }

这里有一个版本相关的坑,来自 fiber 的 CHANGELOG:v7.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 级别的提示警告:不要在useFramesetState;回调计算要精简,并留意循环类代码的常见陷阱。
  • 接管之后渲染完全由你负责:正数优先级存在时 R3F 不再自动渲染(见 loop.ts),如果你注册了正数优先级却忘了调用gl.render,画面将得不到更新。
  • frameloopalways/demand/never)是 Canvas 上另一套渲染模式配置,默认always;本文的接管路径与它相互独立,按需另行查阅 canvas 文档。

如何验证接管生效

文档没有提供专用检查命令,但可以从三个可观察的行为判断:

  1. 自动渲染已被跳过:源码条件!state.internal.priority决定了只要有任何正数优先级的useFrame存在,R3F 就不会再替你调用gl.render(state.scene, state.camera)。把接管组件移出场景树(或注释掉),画面恢复由 R3F 自动渲染,即可反证接管确实生效。
  2. 多次渲染按优先级排序:按文档的说明,优先级1的回调先于优先级2的回调执行。Viewcube 示例中主场景先画、HUD 后画并叠在上方,正是这个顺序的可见结果。
  3. 参考实现可运行:仓库的 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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 22:10:58

SSM+Vue科普网站毕设设计与实现指南

1. 项目概述&#xff1a;SSMVue科普网站毕设设计这个毕设项目采用SSM&#xff08;SpringSpringMVCMyBatis&#xff09;后端框架与Vue.js前端框架的组合架构&#xff0c;目标是构建一个功能完善的科普类网站。作为2026届计算机相关专业的毕业设计选题&#xff0c;它不仅需要实现…

作者头像 李华
网站建设 2026/9/10 22:06:28

NetLogo与Python/R/JS集成实战指南

1. NetLogo与其他软件集成的核心价值在复杂系统建模与仿真领域&#xff0c;NetLogo作为经典的多主体建模工具&#xff0c;其真正的威力往往体现在与其他专业软件的协同工作中。我曾在城市交通流模拟项目中&#xff0c;通过将NetLogo与Python的数据分析能力结合&#xff0c;将原…

作者头像 李华
网站建设 2026/9/10 22:04:11

CANN/ge图引擎API:SetOriginSymbolShape

SetOriginSymbolShape 【免费下载链接】ge GE&#xff08;Graph Engine&#xff09;是面向昇腾的图编译器和执行器&#xff0c;提供了计算图优化、多流并行、内存复用和模型下沉等技术手段&#xff0c;加速模型执行效率&#xff0c;减少模型内存占用。 GE 提供对 PyTorch、Tens…

作者头像 李华