Hi!
I would like to share a code snippet for easy local caching of your 3d assets. I am using Dexie (a minimalistic IndexedDB wrapper). https://dexie.org/
Since this example uses Typescript, it’s a good idea to have a look here how to use Dexie with Typescript: Typescript
The code snippet is taken out from a class thus the method definition in step 4 and usage of this
in step 5.
Let’s start:
-
Install Dexie
npm i dexie
-
import Dexie in your script
import Dexie from 'dexie'
-
define the table and create our database class. The
key
is the remote url of the file. Data is the binary data itself. It is stored as aBlob
object.
interface ICachedModel {
url: string
data: Blob
}
class ModelDatabase extends Dexie {
models: Dexie.Table<ICachedModel, string>
constructor() {
super('ModelDatabase')
this.version(1).stores({
models: 'url, data'
})
this.models = this.table('models')
}
}
- let’s create a method to load from local cache or remote url. The local copy takes precedence. Set
forceRemote
to force loading from the remote url and store the new data in the local cache.
async loadFromUrlOrLocal(
url: string,
filename: string,
scene: Scene,
forceRemote = false
): Promise<ISceneLoaderAsyncResult | null> {
try {
let blob: Blob | null = null
const db = new ModelDatabase()
const key = url + filename
const data = await db.models.get(key)
if (data && !forceRemote) {
// local data available and remote is not forced
blob = data.data
console.log('Loaded from local using key', key, 'size:', blob.size)
} else {
// local data not available or remote is forced
const data = await fetch(url + filename)
blob = await data.blob()
// store in local cache
await db.models.put({
url: key,
data: blob
})
console.log('Loaded from remote url', url + filename, blob.size)
}
if (blob) {
// import from blob to scene
const file = new File([blob], filename, { type: 'application/octet-stream' })
const imported = await SceneLoader.ImportMeshAsync('', '', file, scene)
return imported
}
} catch (e) {
console.error('Failed to load', url + filename, e)
}
// failed to load
return null
}
- now you can use the new method instead of directly call the
SceneLoader.ImportMeshAsync
method.
// const imported = await SceneLoader.ImportMeshAsync('', baseUrl, t.filename, this._scene)
const forceRemote = true // set this for example using document.location.href.indexOf("forceRemote") > -1 or from a config file or whatever source
const imported = await this.loadFromUrlOrLocal(baseUrl, t.filename, this._scene, forceRemote)
if (imported) {
// process the loaded stuff
}
Hope it helps!
R.