前言
大部分的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彪叔” 可以及時收到更多有價值的文章。