threejs loader模块封装 和 模型缓存 indexDB
Three.Js loader封装 和 indexDB缓存模型
支持各种格式(glb、gltf、fbx、obj、mtl)
indexDB 缓存 和列表形式加载
在three项目中需要加载很多的模型 而且在很多地方需要使用loader加载模型回调的gltf
上一个项目中遇到了 第一次不会也遇到好多坑 下面是我整理的封装
话不多说 直接上代码吧!(菜鸡程序媛 请指导qaq)
极简
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
const loader = new GLTFLoader();
export const loadStore = function(){
return new Promise((resolve, reject) => {
loader.load("./gltf/xxx.gltf", gltf => {
model.add(gltf.scene);
model.position.set(-40.5325,-30.1916,0)
resolve(gltf)
});
})
}
带清除模型的
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
const loader = new GLTFLoader();
let model = new THREE.Group();
export const loaderModel = function (path) {
return new Promise(resolve => {
loader.load(path, function (gltf) {
// 移除模型
if(model.children.length){
model.children.forEach(item=>{
model.remove(item)
})
}
model.add(gltf.scene);
resolve(gltf)
});
})
}
export { model };
终极版
-
可批量load
-
支持多种格式
-
支持indexDB 缓存
utils 中的方法 均为lodash 的方法
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader.js';
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js';
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
import utils from "utils";
import * as THREE from "three";
import DBUtils from "@/common/_/threejs/DBUtils";
var serverAddress = window.location.host; // 获取服务器地址
//params 为引入的模型地址或者地址集合 handleProgress 为 回调函数 用于计算加载进度
export default function loader(params, handleProgress) {
// 批量加载资源
// lodash 中的 isArray 方法
if (utils.isArray(params)) {
let funcarr = [];
let progressEvent = {
loaded: {},
total: {}
}
// lodash 中的 throttle 节流 方法
let update = utils.throttle(() => {
let loaded = 0, total = 0;
// lodash 中的 each 方法
utils.each(progressEvent.loaded, (v) => {
loaded += v;
});
utils.each(progressEvent.total, (v) => {
total += v;
});
// console.log(loaded, total);
handleProgress({
loaded,
total
})
}, 100);
let func = (i) => {
// console.log('func', progressEvent);
return (o) => {
progressEvent.loaded[i] = o.loaded;
progressEvent.total[i] = o.total;
update();
}
};
params.forEach((p, i) => {
funcarr.push(loader(p, func(i)))
});
return Promise.all(funcarr);
}
return new Promise(resolve => {
let path = params.path;
let ext = utils.getFileType(path);
let loader;
switch (ext) {
case 'glb':
case 'gltf':
if (params.decoderPath) {
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath(params.decoderPath);
loader = new GLTFLoader();
loader.setDRACOLoader(dracoLoader);
}
else {
loader = new GLTFLoader();
}
break;
case 'obj':
if (params.mtl) {
return new Promise(resolve => {
var mtlLoader = new MTLLoader();
// 初始化obj
var objLoader = new OBJLoader();
// 加载mtl文件
mtlLoader.load(params.mtl, (mtl) => {
// 初始化
mtl.preload();
// 加载贴图
objLoader.setMaterials(mtl);
objLoader.load(path, (obj) => {
resolve({ mtl, obj })
}, handleProgress);
})
});
}
else {
loader = new OBJLoader();
}
break;
case 'mtl':
loader = new MTLLoader();
break;
case "fbx":
loader = new FBXLoader();
break;
}
if (loader) {
if (//需要缓存的条件) {
const indexDB = new DBUtils("gltf", "shengwei");
// 此处拼 服务器地址
indexDB.get('http://'+serverAddress + '/' + path)
.then((blob) => {
path = URL.createObjectURL(new Blob([blob]));
loader.load(path, (res) => {
resolve(res);
}, handleProgress)
});
} else {
loader.load(path, (res) => {
resolve(res);
}, handleProgress)
}
}
});
}
DBUtils 缓存的代码
export default class DBUtils {
constructor(dbName, storeName, dbVersion = 1) {
this.dbName = dbName;
this.storeName = storeName;
this.dbVersion = dbVersion;
this.db = null;
}
async get(url) {
this.db = await this.initDataBase(this.dbName, this.storeName, this.dbVersion);
const request = this.db
.transaction([this.storeName], 'readwrite')
.objectStore(this.storeName)
.get(url);
return new Promise((resolve, reject) => {
request.onsuccess = evt => {
const modelFile = evt.target.result;
console.log(modelFile);
// 如果缓存中有,直接从缓存中获取
if (modelFile) {
console.log("使用缓存");
resolve(modelFile.blob);
} else {
console.log("请求资源");
// 如果缓存中没有,则请求资源
this.addData(url).then(blob => {
resolve(blob);
}).catch(() => {
reject();
});
}
};
request.onerror = evt => {
console.log('error', evt);
reject();
};
});
}
终极版使用
loader(option.load, (progressEvent) => {
this.percentage = +(progressEvent.loaded * 99 / progressEvent.total).toFixed(2);
}).then(res => {
this.loading = false;
this.init();
if (!this.on.load) {
console.error("option.on.load方法不存在");
}
else {
this.on.load(this, res);
}
});