关于前端:WebGL加载本地模型

53次阅读

共计 2516 个字符,预计需要花费 7 分钟才能阅读完成。

前言

大部分的 webgl 框架,比方 threejs 和 babylon 等,都能够加载 obj 和 gltf 模型。咱们的引擎,基于 three 封装,同样有加载模型的 loader,因而加载 obj 和 gltf 模型也是很简略就能够实现的。

不过加载文件都是在线的文件,也就是通过 url 的模式进行加载。团队开发的三维可视化平台框架,须要可能上传 obj 和 gltf 等格局的模型,在上传前,须要先对模型预览,这就波及到如何加载本地模型的问题了。

加载本地模型

本文以 gltf 为例,进行阐明。加载本地模型的思路是这样的:
既然引擎能够通过 url 的机制,加载模型。那么如果有一种机制,能够把本地文件及其关联的资源(比方贴图)等转换成 url 的模式,就能够进行应用 loader 进行拜访了。

Blob & File

首先咱们学习下 Blob 和 File 对象,以下内容来自 MDN:

Blob 对象示意一个不可变、原始数据的类文件对象。它的数据能够按文本或二进制的格局进行读取,也能够转换成 ReadableStream 来用于数据操作。

Blob 示意的不肯定是 JavaScript 原生格局的数据。File 接口基于 Blob,继承了 blob 的性能并将其扩大使其反对用户零碎上的文件。

File 对象是非凡类型的 Blob,且能够用在任意的 Blob 类型的 context 中。比如说,FileReader, URL.createObjectURL(), createImageBitmap() (en-US)”), 及 XMLHttpRequest.send()) 都能解决 Blob File

createObjectURL

URL 对象上的办法 createObjectURL 能够把一个 Blob 对象或者 File 对象,转化成一个 url 对象,语法如下:

objectURL = URL.createObjectURL(object);

其中 object 示意的是 Blob 或者 File 对象。返回的是一个 url 地址对象。

加载本地模型

有了上述基础知识,大抵的思路就进去了:

  • 首先 加载本地文件,读取 file 对象(可能是多个 File 对象,因为一个模型可能包含多个资源文件)。
  • 找出次要文件(gltf glb 等格局的)文件,主文件通过 createObjectURL 办法转换成 url 对象
  • 找出其余文件,通过 createObjectURL 办法转换成 url 对象
  • 加载主文件的 url,并在加载过程中,通过地址改写的形式,把相干的资源替换成文件的 url 对象。

以上思路的大抵代码如下:

let files = document.getElementById("file-input").files;

          if (!files.length) return;
          console.log(files);
          let rootFile;
          const fileMap = new Map();
          Array.from(files).forEach((file) => fileMap.set(file.name, file));
          Array.from(fileMap).forEach(([path, file]) => {if (file.name.match(/\.(gltf|glb)$/)) {
              rootFile = file;
              rootPath = path.replace(file.name, "");
            }
          });
          const fileUrl = URL.createObjectURL(rootFile);
          const gltf = await load(fileUrl, rootPath, fileMap);

function load(url, rootPath, assetMap) {const index = url.lastIndexOf("/");
      const baseURL = index === -1 ? "./" : url.substr(0, index + 1);
      const manager = new dt.LoadingManager();
      // Load.
      return new Promise((resolve, reject) => {manager.setURLModifier((url, path) => {
          const normalizedURL =
            rootPath +
            decodeURI(url)
            .replace(baseURL, "")
            .replace(/^(\.?\/)/, "");

          if (assetMap.has(normalizedURL)) {const blob = assetMap.get(normalizedURL);
            const blobURL = URL.createObjectURL(blob);
            blobURLs.push(blobURL);
            return blobURL;
          }
          return (path || "") + url;
        });
        const loader = new dt.GLTFLoader(manager).setCrossOrigin("anonymous");
        loader.setDRACOLoader(new dt.DRACOLoader());
        loader.setMeshoptDecoder(MeshoptDecoder);
        const blobURLs = [];
        let time = new Date().getTime();
        loader.load(url,(gltf) => {const scene = gltf.scene || gltf.scenes[0];
            const clips = gltf.animations || [];
            if (!scene) {throw new Error("This model contains no scene");
            }
            console.log("delta", new Date().getTime() - time);
            blobURLs.forEach(URL.revokeObjectURL);
            resolve(gltf);
          },
          undefined,
          reject
        );
      });
    }

总结

通过上述形式,能够写简略工具,帮忙开发和建模人员随时查看模型的状况。


除 gltf 模型外,其余格局的模型,比方 fbx 或者 obj,也能够相似操作。

如果对可视化感兴趣,能够和我交换,微信 541002349。关注公号“ITMan 彪叔”能够及时收到更多有价值的文章。

正文完
 0