我正在React内的three.js场景中加载约10MB的GLTF模型。用户浏览网站时,他们点击了3D模型“场景”,并加载了我的GLTF模型。当他们完成这个场景时,我将卸载react组件之前进行一点Threejs清理。但是,如果用户重新访问此场景-它会再次经历整个加载过程。
有一种方法可以某种方式将加载的对象保留在浏览器缓存中,以便即使在卸载react组件之后,也可以访问已加载的模型数据以供后续访问 /组件安装(即使它仅位于同一组件中浏览器会话,刷新之前等)?
这是模型加载代码:
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层次之外?这样,您可以将画布放置在任意位置(例如,在背景中),并且可以打开/关闭画布的可见性,而不必每次想要显示/隐藏画布时都启动新的WebGL上下文。您可以简单地停止渲染并在CSS中设置display: none
以隐藏画布,同时仍将所有内容保留在备用状态以备您再次需要时使用。
类似这样的东西:
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/上使用的方法,我们在后台只有一个画布,并且只启动一次。然后,我们根据需要显示/隐藏它,而无需每次都安装和卸载新组件。