javascript - 即使在卸载/强制上下文丢失后,也会在浏览器缓存中保持加载的 gltf
javascript - maintain loaded gltf in browser cache even after unmount / force context loss
我正在将大约 10MB 的 GLTF 模型加载到 React 中的 three.js 场景中。当用户浏览网站体验时,他们点击了 3D 模型 "scene",并且加载了我的 GLTF 模型。当他们完成这个场景时,我会做一些 threejs 清理,然后再卸载 React 组件。然而,如果用户重新访问这个场景——它会再次经历整个加载过程。
有没有办法以某种方式将加载的对象保存在浏览器缓存中,以便即使在卸载 react 组件后,后续访问也可以访问加载的模型数据 / component挂载(即使它仅在同一个浏览器会话中,在刷新之前等)?
这是模型加载代码:
loadGLB = loader => {
if (sceneConfig.modelFormat === 'glb') {
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('three/examples/js/libs/draco/');
loader.setDRACOLoader(dracoLoader);
}
};
const loader = new GLTFLoader().setPath(models.modelPath);
this.loadGLB(loader);
loader.load(`${models.modelToLoad}.${sceneConfig.modelFormat}`, glb => {
this.object = glb.scene;
...
});
和清理:
componentWillUnmount() {
cancelAnimationFrame(this.frameId);
window.removeEventListener('resize', this.handleWindowResize);
this.container.removeChild(this.renderer.domElement);
this.renderer.forceContextLoss();
}
在同一页面上多次重新启动新的 WebGL 上下文有一些性能缺陷。最重要的是,每个新上下文都必须将所有纹理和几何图形重新上传到 GPU,这是导致帧交错和闪烁的瓶颈。更不用说您通过清理 + 重建渲染器、着色器、几何图形、纹理等积累的所有内存和 GC 开销。这是轶事,但 FireFox 通常在创建其第 3 或第 4 个 WebGL 时对我来说陷入困境上下文,当内存消耗过高时,我让移动设备完全重新加载页面。
您是否尝试过使用 Portals 以便 <canvas>
在 React 层次结构之外?通过这种方式,您可以将 canvas 放置在任何您喜欢的位置(例如,在后台)并且您可以改变它的可见性 on/off 而不必每次都启动一个新的 WebGL 上下文 show/hide 它。您可以简单地停止渲染并在 CSS 中设置 display: none
以隐藏 canvas,同时仍然让所有内容处于待机状态以备您再次需要时使用。
像这样:
if (enabled) {
renderer.render(scene, cam);
renderer.domElement.style.display = "block";
} else {
// Not rendering when canvas is hidden
renderer.domElement.style.display = "none";
}
这是我们在 https://madeinhaus.com/ 上使用的方法 我们在后台有一个 canvas,我们只启动它一次。然后我们show/hide根据需要它而不是每次安装和卸载一个新的组件。
我正在将大约 10MB 的 GLTF 模型加载到 React 中的 three.js 场景中。当用户浏览网站体验时,他们点击了 3D 模型 "scene",并且加载了我的 GLTF 模型。当他们完成这个场景时,我会做一些 threejs 清理,然后再卸载 React 组件。然而,如果用户重新访问这个场景——它会再次经历整个加载过程。
有没有办法以某种方式将加载的对象保存在浏览器缓存中,以便即使在卸载 react 组件后,后续访问也可以访问加载的模型数据 / component挂载(即使它仅在同一个浏览器会话中,在刷新之前等)?
这是模型加载代码:
loadGLB = loader => {
if (sceneConfig.modelFormat === 'glb') {
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('three/examples/js/libs/draco/');
loader.setDRACOLoader(dracoLoader);
}
};
const loader = new GLTFLoader().setPath(models.modelPath);
this.loadGLB(loader);
loader.load(`${models.modelToLoad}.${sceneConfig.modelFormat}`, glb => {
this.object = glb.scene;
...
});
和清理:
componentWillUnmount() {
cancelAnimationFrame(this.frameId);
window.removeEventListener('resize', this.handleWindowResize);
this.container.removeChild(this.renderer.domElement);
this.renderer.forceContextLoss();
}
在同一页面上多次重新启动新的 WebGL 上下文有一些性能缺陷。最重要的是,每个新上下文都必须将所有纹理和几何图形重新上传到 GPU,这是导致帧交错和闪烁的瓶颈。更不用说您通过清理 + 重建渲染器、着色器、几何图形、纹理等积累的所有内存和 GC 开销。这是轶事,但 FireFox 通常在创建其第 3 或第 4 个 WebGL 时对我来说陷入困境上下文,当内存消耗过高时,我让移动设备完全重新加载页面。
您是否尝试过使用 Portals 以便 <canvas>
在 React 层次结构之外?通过这种方式,您可以将 canvas 放置在任何您喜欢的位置(例如,在后台)并且您可以改变它的可见性 on/off 而不必每次都启动一个新的 WebGL 上下文 show/hide 它。您可以简单地停止渲染并在 CSS 中设置 display: none
以隐藏 canvas,同时仍然让所有内容处于待机状态以备您再次需要时使用。
像这样:
if (enabled) {
renderer.render(scene, cam);
renderer.domElement.style.display = "block";
} else {
// Not rendering when canvas is hidden
renderer.domElement.style.display = "none";
}
这是我们在 https://madeinhaus.com/ 上使用的方法 我们在后台有一个 canvas,我们只启动它一次。然后我们show/hide根据需要它而不是每次安装和卸载一个新的组件。