foreword

Most webgl frameworks, such as threejs and babylon, can load obj and gltf models. Our engine, based on the three package, also has a loader for loading models, so loading obj and gltf models is also very simple.

However, the loaded files are all online files, that is, they are loaded in the form of url. The 3D visualization platform framework developed by the team needs to be able to upload models in formats such as obj and gltf. Before uploading, the model needs to be previewed, which involves how to load the local model.

load local model

This article takes gltf as an example to illustrate. The idea of loading a local model is as follows:
Since the engine can load the model through the url mechanism. Then if there is a mechanism that can convert local files and their associated resources (such as textures) into the form of url, they can be accessed using loader.

Blob & File

First, let's learn about Blob and File objects. The following is from MDN:

Blob object represents an immutable, raw data file-like object. Its data can be read in text or binary format, or converted toReadableStream for data manipulation.

Blobs do not necessarily represent data in a JavaScript-native format. File interface is based on Blob , inherits the functionality of blobs and extends it to support files on the user's system.

File objects are of special type Blob and can be used in any context of type Blob.比如说, FileReader , URL.createObjectURL() , createImageBitmap() (en-US) "), 及XMLHttpRequest.send() ) 都能处理Blob and File .

createObjectURL

The method createObjectURL on the URL object can convert a Blob object or a File object into a url object. The syntax is as follows:

 objectURL = URL.createObjectURL(object);

The object represents a Blob or File object. What is returned is a url address object.

load local model

With the above basic knowledge, the general idea comes out:

  • First load the local file, read the file object (may be multiple File objects, because a model may include multiple resource files).
  • Find the main file (gltf glb and other formats) file, the main file is converted into a url object through the createObjectURL method
  • Find other files and convert them into url objects through the createObjectURL method
  • Load the url of the main file, and replace the related resources with the url object of the file by means of address rewriting during the loading process.

The rough code of the above idea is as follows:

 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
        );
      });
    }

Summarize

In the above way, simple tools can be written to help developers and modelers to see the situation of the model at any time.

image.png
In addition to gltf models, other formats of models, such as fbx or obj, can also be operated similarly.

If you are interested in visualization, you can communicate with me on WeChat 541002349. Pay attention to the public account "ITMan Biao Shu" to receive more valuable articles in time.


netcy
204 声望120 粉丝

欢迎对canvas、webgl、图形学感兴趣的读者订阅专栏。