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);
                }
            });
posted @ 2024-03-19 11:20  宝贝熊の  阅读(622)  评论(0编辑  收藏  举报