前言

应用webgl开发三维利用的时候,常常会发现三维场景加载比较慢,往往须要期待挺长时间,这样用户的体验就很不敌对。 造成加载慢的起因,次要是三维利用波及到的资源文件会特地多,这些资源文件次要是模型及其图片,往往这些模型和图片都会比拟大。

为了放慢三维场景的加快速度,能够应用IndexedDB在客户端进行资源缓存。IndexedDB,即客户端长久化数据库!应用本缓存技术,在首次拜访后,3D场景中的文件级别数据将写入拜访设施本地缓存数据库,在客户端实现永恒的生命周期,革除浏览器缓存也不影响已缓存的3D模型文件。

IndexedDB介绍

IndexedDB 是一个前端数据长久化解决方案(即前端缓存),由浏览器实现。
IndexedDB又如下特点

  • 基于文件存储。意味着其容量可达到硬盘可用空间下限
  • 非关系型数据库。意味着扩大或膨胀字段个别毋庸批改数据库和表构造(除非新增字段用做索引)
  • 键值对存储。意味着存取毋庸字符串转换过程
  • 存储类型丰盛。意味着浏览器缓存中不再是只能存字符串了
  • 异步: 意味着所有操作都要在回调中进行

本地浏览器领有三种永恒存储数据技术,别离为Web Storage、IndexedDB、Web SQL。IndexedDB具备查问高效、存储空间大和异步操作等技术特色,有微小的劣势。

存储空间大。IndexedDB 的贮存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有下限。在HTML5本地存储中,IndexedDB存储的数据则是最多的。

查问高效。IndexedDB是一种轻量级NOSQL数据库,是由浏览器自带。相比Web Sql更加高效,包含索引、事务处理和查问性能。

异步操作。 IndexedDB 操作时不会锁死浏览器,用户仍然能够进行其余操作,这与 LocalStorage 造成比照,后者的操作是同步的。异步设计是为了避免大量数据的读写,拖慢网页的体现。

与此同时,IndexedDB 外部采纳对象仓库存放数据。所有类型的数据都能够间接存入,包含 JavaScript 对象,满足了三维场景的存储须要。

因而 应用IndexedDB缓存是一种最为优异的前端缓存计划。像Babylon.js,其引擎层面曾经反对了IndexedDB缓存。能够参考如下文档:
https://doc.babylonjs.com/div...。

three.js应用IndexedDB的思路

无关具体如何应用IndexedDB,有很多材料进行介绍,此文不在赘述。

应用IndexedDB缓存模型资源,首先须要获取模型相干的资源,这些模型资源包含模型文件以及相干的图片文件。 比方对于GLTF模型而言,其资源包含.gltf的模型主文件,.bin格局的文件,纹理贴图文件等等。 首次加载加一个模型的时候,必定是加载网络上的资源文件,通过threejs的LoadingMananger能够收集一个gltf模型的各种资源文件。 代码如下:

    const resourceCollector = [];    const loadingManager = new LoadingManager();    loadingManager.setURLModifier( (url,path) => {      console.log(url);      if(url.startsWith("data:") || url.startsWith("blob:")) {        return url;      }      resourceCollector.push(url);      return url;    });

上述代码resourceCollector收集了加载模型过程中所有的模型资源的地址。 收集之后把所有资源存储到IndexedDB中:

saveGltfModel:async function(options,resourceCollector){    const gltfUrl = options.gltfPath;    const blobs = {};    for(let i = 0;i < resourceCollector.length;i ++) {      let url = resourceCollector[i];      let blob = await loadAsBlob(url);      blobs[url] = blob;      await addToDatabase("model",{key:url,blob})    }    await addToDatabase("model_info",{key:gltfUrl,content:resourceCollector});  },

其中loadAsBlob是把一个资源加载成为blob对象,代码如下:

  const xhr = new XMLHttpRequest();  xhr.open("GET", url);  xhr.responseType = "blob";  xhr.onerror = function() {reject("Network error.")};  xhr.onload = function() {      if (xhr.status === 200) {resolve(xhr.response)}      else {reject("Loading error:" + xhr.statusText)}  };  xhr.send();

而addToDatabase办法把资源增加到IndexedDB数据库。

function addToDatabase(storename, data) {  const promise = new Promise( (resolve,reject) => {    let store = database.transaction(storename, 'readwrite').objectStore(storename);    let countReq = store.count(data.key);    countReq.onsuccess = function(event) {      console.log("count:",event.target.result);      let count = event.target.result;      if(count ==  0) {        let request = store.add(data);        request.onerror = function (event) {          console.error('add增加数据库中已有该数据')          reject(event);        };        request.onsuccess = function (event) {          console.log('add增加数据已存入数据库')          resolve(event);        };      }    };  });}

下一次获取模型的时候,能够先判断是否以及本地存储,如果曾经本地存储,就能够间接从本地获取模型资源:

 if(this.indexDbCache && indexedDB) {      if(database == null) {        database = await initialDB();      }      const storeObject = await findInDatabase("model_info",key);      if(storeObject) {        return this.loadGltfInDb(options);      }    }

缓存成果测评

通过测试能够发现对于比拟大的场景,模型加载的速度能够进步几倍,十几倍甚至几十倍。 由此可见,IndexedDB缓存成果很显著。

如果对可视化感兴趣,能够和我交换,微信541002349。

关注公号“ITMan彪叔” 能够及时收到更多有价值的文章。