前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WebGL加载本地模型

WebGL加载本地模型

作者头像
用户3158888
发布2022-05-11 14:54:57
1.7K0
发布2022-05-11 14:54:57
举报

前言

大部分的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对象,语法如下:

代码语言:javascript
复制
objectURL = URL.createObjectURL(object);

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

加载本地模型

有了上述基础知识,大致的思路就出来了:

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

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

代码语言:javascript
复制
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
        );
      });
    }

总结

通过上述方式,可以写简单工具,帮助开发和建模人员随时查看模型的情况。

image.png
image.png

除gltf模型外,其他格式的模型,比如fbx或者obj,也可以类似操作。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-05-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 加载本地模型
  • Blob & File
  • createObjectURL
  • 加载本地模型
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档