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); } });
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】