@14个岛屿/r3f-scroll-rig
使用 WebGL 逐步增强反应网站 @react-three/fiber 并展开平滑的卷轴.
[ 特征 | 导言 | 安装 | 开始 | 实例 | API 密码 | 抓到他们了 [ . ]
特征
- QQ 跟踪 DOM 元素, 并用正确的比例和位置来绘制 Three.js 对象的位置 .
- • 框架不可知 - 与
next.js, (中文(简体) ),gatsby.js, (中文(简体) ),create-react-app包括:. - * 可在取景口中渲染物体。 使每个物体都有可能拥有独特的相机,灯光,环境图等.
- 帮助从 DOM 装入响应图像 。 支助
<picture>, (中文(简体) ),srset财务报告和审定财务报表loading="lazy" - 最佳表现。 电话
getBoundingClientRect()一旦挂载,并使用交叉观察员/抵抗观察员来跟踪各项要素. - 用户 列尼斯语Name 用于可访问的平滑滚动
- 百分之百符合@反应-三生态系统 德莱, (中文(简体) ), 反应-春季 财务报告和审定财务报表 反应-xr
导言
用滚动的HTML来混合WebGL是困难的. 一种方式是拥有多幅画布,但对于WebGL中有多少个背景可以同时活跃,资源不能在上下文之间共享,有特定浏览器的限制.
卷轴里格只有一个共享 <GlobalCanvas/> 在页面负载之间.
反应 DOM 组件可以选择在使用自定义钩子挂载时在此画布上绘图 useCanvas() 或 <UseCanvas/> 隧道组件.
库还提供了在滚动时将WebGL对象与DOM同步的手段. 我们使用一种技术,跟踪正常页面流中的“代理”元素,并更新WebGL场景位置,以匹配它们.
这个 <ScrollScene/>, (中文(简体) ), <ViewportScrollScene/> 或基础 useTracker() 钩会检测代理元素的初始位置和尺寸,并更新滚动时的位置.
所有东西都与主线上滚动条位置同步.
进一步读作: 用 WebGL 和 React 进行渐进增强
正在安装QQ
yarn add @14islands/r3f-scroll-rig @react-three/fiber three
开始QQ
-
添加
<GlobalCanvas>到您的布局。 将其保存在路由器外,以防在页间导航时卸载. -
添加
<SmoothScrollbar/>到您的布局。 为了完全匹配WebGL对象和DOM内容,浏览器卷轴位置需要在主线程上被动画.
下一个.js
import { GlobalCanvas, SmoothScrollbar } from '@14islands/r3f-scroll-rig'
// _app.jsx
function App({ Component, pageProps }: AppProps) {
return (
<>
<GlobalCanvas />
<SmoothScrollbar />
<Component {...pageProps} />
</>
)
}
盖茨比.js
// gatsby-browser.js
import { GlobalCanvas, SmoothScrollbar } from '@14islands/r3f-scroll-rig'
export const wrapRootElement = ({ element }) => (
<>
<GlobalCanvas />
<SmoothScrollbar />
{element}
</>
)
- 跟踪 DOM 元素并制取一个 3.js 对象
这是追踪DOM的组件的基本例子
import { UseCanvas, ScrollScene } from '@14islands/r3f-scroll-rig'
export const HtmlComponent = () => (
const el = useRef()
return (
<>
<div ref={el}>Track me!</div>
<UseCanvas>
<ScrollScene track={el}>
{(props) => (
<mesh {...props}>
<planeGeometry />
<meshBasicMaterial color="turquoise" />
</mesh>
)}
</ScrollScene>
</UseCanvas>
</>
)
)
如何运作:
- 页面布局使用普通 HTML & CSS 样式
- 这个
UseCanvas用于将孩子送到GlobalCanvas当组件挂起时 - A 类
<Scrollscene>用于跟踪 DOM 元素 - 内部
<ScrollScene>我们定出一个网状的网状,它将作为已逝的一部分,获得正确的分寸props
注释: HMR可能不为下列儿童服务: <UseCanvas> 除非你在外边定义了他们 此外,儿童身上的道具默认并非被动反应,因为部件被通向全球帆布. 更新道具需要这样通地道.
了解更多关于边缘案例和解决方案 获取区域。 。 。 .
实例
- 滚动环境基本实例
- 由 DOM 和 Canvas 提供的 GLB 模型和事件滚动
- 带有自定义相机和控件的 ViewportScrollScene
- 从“ img” 标签装入纹理
- 从 DOM 装入响应的纹理
- HTML 参数使用跟踪器( ) 和帧器运动
- 电源样品的粘相卷轴
- 一个基本的后处理示例
API —— ——
所有组件和钩在 API 文件
构成部分 |
钩子 |
抓住他们了
默认相机
默认的卷轴-rig相机被锁定到50度的场景.
为了完全匹配DOM尺寸,将计算相机相距. 这种计算基于屏幕高度,因为Treejs使用垂直的FOV. 这意味着相机位置 -z会根据你的身高稍作改变.
您可以覆盖默认相机行为, 例如设置距离, 并有一个可变的 FOV :
<GlobalCanvas camera={{ position: [0, 0, 10] }} />
或改变FOV, 它可以移动相机 更远在这种情况下:
<GlobalCanvas camera={{ fov: 20 }} />
如果您需要完全控制相机,您可以在孩提时用自定义相机通过.
使用相对缩放
大小始终以从ScrollScene/ViewportScrollScene/useTracker上传下来的"比例尺"为基准,以便所有屏幕大小的缩放一致.这个 scale 总是匹配跟踪的 DOM 元素,并将根据媒体查询等进行更新.
<ScrollScene track={el}>
{{ scale }} => (
<mesh scale={scale} />
)}
</ScrollScene>
缩放为 三维向量类型 维克恩 支持擦去和标注对象。 你可以做这样的事情:
position.x === position[0]
position.xy => [x,y]
scale.xy.min() => Math.min(scale.x, scale.y)
3D 对象上的 Z- 战斗( 比例倍增器)
默认情况下,卷轴-rig会计算相机FOV,这样一像素=一取景器单元.
在某些情况下,这可能会搅乱深度排序,导致3D模型中的视觉出故障. 1000像素宽屏幕会让场景1000取景器单元宽,默认情况下相机也会被定位为~1000个单元去Z轴(取决于FoV和屏幕高特).
一个解决的方法就是使 对数深度缓冲 但是这可能会对表现不利.
更好的解决问题的方法就是改变全球危机 scaleMultiplier 喜欢的东西 0.01 这将使1000px = 10个取景器单元.
<GlobalCanvas scaleMultiplier={0.01} />
这个 scaleMultiplier 设置所有内部相机和缩放逻辑。 如果您更改了此设置, 需要更新已编码的缩放和位置 .
匹配精确的十六进制颜色
默认的R3F使用ACES Filmic语调映射,使得3D场景看起来很棒.
然而,如果需要匹配六分法颜色或显示编辑图像,可以禁用每个类似材料:
<meshBasicMaterial toneMapping={false} />
累积布局变化( CLS)
页面上的所有项目都应有一个可预测的高度——始终使用CSS来定义图像和其他可能影响到文件加载时高度的交互式元素的宽比.
滚动指针使用 ResizeObserver 以检测对 document.body 高度, 例如在 webfonts 装入后, 并且会自动重新计算所装的 .
如果因某种原因失败, 可以触发手动操作 reflow() 以重新计算所有缓存位置.
const { reflow } = useScrollRig()
useEffect(() => {
heightChanged && reflow()
}, [heightChanged])
绩效提示
- 尽可能使用 CSS 动画,而不是 JS ,以尽量平滑
- 考虑取消平滑Scrollbar和移动上所有滚动的WebGL元素的功能 - 它通常是拉吉.
- 确保你 阅读、理解和跟踪所有业绩建议 与
React财务报告和审定财务报表three数字 :
如何捕捉来自DOM和Canvas的事件
这在R3F中是可能的,方法是将事件系统重新连接到画布的母部分:
const ref = useRef()
return (
<div ref={ref}>
<GlobalCanvas
eventSource={ref} // rebind event source to a parent DOM element
eventPrefix="client" // use clientX/Y for a scrolling page
style={{
pointerEvents: 'none', // delegate events to wrapper
}}
/>
</div>
)
我能在“视频空间”中使用R3F事件吗?
是的,如果您遵循上述步骤将事件系统重新连接到画布的母部分, 事件将会被正确地通入视图端口 .
在 Viewport 中 Margin 无法在代码对话框中工作
代码Sandbox 编辑器运行在一个 iframe 中, 它打破了 Intersection 观察器 rootMargin。如果你打开 iframe 外的示例, 你会看到它的工作原理.
这是知道 问题。 。 。 .
HMR不与UseCanvas儿童合作
有问题 UseCanvas 组件.
你也可以用这个 useCanvas() 钩子,或者通过定义您的孩子为顶级功能, 而不是内衬, 使 HMR 再次工作 :
// HMR will work on me since I'm defined here!
const MyScrollScene = ({ el }) => <ScrollScene track={el}>/* ... */</ScrollScene>
function MyHtmlComponent() {
return (
<UseCanvas>
<MyScrollScene />
</UseCanvas>
)
}
类似 问题 存在于 tunnel-rat。 。 。 .
全局渲染环路
卷轴-rig运行自定义渲染环球场景在r3f内部的循环. 优先运行 1000。 。 。 .
您可以使用 globalRender 或用 globalPriority 道具装上 <GlobalCanvas>。仍然可以使用 useFrame 您的自定义优先级.
运行我们自己的自定义让通过 而不是默认的 R3F 渲染, 的主要原因是当没有 meshes 在视图中时能够避免渲染。 要启用此功能, 您需要设置 frameloop="demand" (原始内容存档于2012-10-12). On the Global Canvas.
高级 - 按需运行帧
如果设置为 R3F 帧 demand - 卷轴钻机会确保 全球性 和视图端 只有在需要它的情况下.
请求全局渲染呼叫 requestRender() 从 useScrollRig 每个框. ScrollScene 等网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状网状.
这个库还支持在取景口中进行单独的场景,作为单独的渲染通过调用 renderViewport()。这样我们就可以用单独的灯光 或不同的相机来制作场景 与全球场景不同。 就是这样 ViewportScrollScene 工作时.
在这种情况下,你还需要打电话 invalidate 以触发新的 R3F 框架.
如何使用后处理
后处理在单独的通道中运行,所以需要手动禁用全局渲染回路,以避免重复渲染.
<GlobalCanvas globalRender={false} scaleMultiplier={0.01}>
<Effects />
</GlobalCanvas>
说明: ViewportScrollScene 将不受全球后处理效应的影响,因为它运行在单独的转折中.
我怎么能把我的UseCanvas meshes 装入一个共享的悬念?
请在使用时读取 API 文件 儿童作为渲染功能 举个例子.