【three.js : 3D】【loader】THREE.js中載入不同格式的模型及動畫(fbx、json和obj)
轉載:THREE.js中載入不同格式的模型及動畫(fbx、json和obj)
注:本文章內容基於 Three.js 88dev 實現
作為剛接觸three.js的小萌新,勵志將自己開荒歷程記錄下來,希望對後來人有所幫助。
網上有很多demo,文件卻不多。每次都是,照搬別人的資料沒問題,換成自己的模型/動畫總會報錯! (╯‵□′)╯︵┻━┻
多次踩坑後,總結出三種常用格式的載入方法。
1、fbx檔案
three.js有官方的fbx外掛,可以直接將模型載入至網頁,並且支援動畫資料,程式碼量也是最少的。
但是,該格式存在很大弊端:外掛對檔案格式的規範很嚴格,換言之,外掛支援性不太好。從網上下載的fbx動畫,十有八九會載入失敗。
首先需要引入FBXLoader.js外掛,如果報錯 “Error: THREE.FBXLoader: External library Inflate.min.js required, obtain or import from https://github.com/imaya/zlib.js”,則還需引入inflate.min.js檔案。
var fbx_loader = new THREE.FBXLoader(manager);
1.1、靜態模型
fbx_loader.load('./models/miku/miku.fbx', function(object) { object.scale.multiplyScalar(.1); // 縮放模型大小 scene.add(object); }, onProgress, onError);
fbx靜態模型
1.2、動畫
fbx_loader.load('./models/gf/run.fbx', function(object) { object.mixer = new THREE.AnimationMixer(object); mixers.push(object.mixer); var action = object.mixer.clipAction(object.animations[0]); action.play(); object.scale.multiplyScalar(.5); scene.add(object); }, onProgress, onError);
fbx動畫
1、如果遇到報錯 “URIError: URI malformed”,說明fbx檔案格式不符合外掛要求。可能是fbx版本過低導致的。
檢測方法:
新版blender匯入該fbx檔案,如果提示 “Version xxxx unsupported, must be xxxx or later”,說明你的模型檔案版本太低。
解決方案有三:
(1)匯入3dmax,再重新匯出成fbx檔案,將低版本轉換為最新版本。經實踐,雖然在3dmax和blender中動畫顯示正常,但是載入網頁後模型變得支離破碎。可能是座標丟失,目前還在尋找原因及解決辦法。
fbx低版本轉高版本後,座標丟失
(2)用官方提供的外掛將fbx檔案轉換成json動畫資料。
(3)根據 [blender]version 6100 unsupported,must be 7100 or later問題怎麼辦 提供的方法,可通過FBX_Converter_2013將低版本fbx轉換成可支援的fbx檔案,親測可用。
2、如果遇到報錯 “TypeError: Cannot read property 'has' of undefined”,同樣是因為模型檔案不符合規範。
檢測方法:
Chrome Devtools斷點除錯,你會發現很多引數都是undefined。
解決方案:
同上(2)。
2、json檔案
three.js自帶了載入json的方法,所以不需要額外引用外掛。
Three.js展示模型問題總結 中講到:
現在的JSON格式有兩個型別,一個是Geometry型別,需要JSONLoader載入;一個是Object型別,需要ObjectLoader載入。
用錯loader.js的話,會報錯 “THREE.ObjectLoader: Can't load xxx.json. Use THREE.JSONLoader instead.” 或者 “THREE.JSONLoader: xxx.json should be loaded with THREE.ObjectLoader instead.”。
2.1、靜態模型
2.1.1、Geometry型別
var js_loader = new THREE.JSONLoader(manager);
js_loader.load('./models/hmj/frame001.json', function(geometry, materials) {
var material = new THREE.MultiMaterial(materials); // 多個紋理
var mesh = new THREE.Mesh(geometry, material);
mesh.scale.multiplyScalar(.06);
scene.add(mesh);
}, onProgress, onError);
json靜態模型 - Geometry型別
2.1.2、Object型別
var object_loader = new THREE.ObjectLoader(manager);
object_loader.load('./models/teapot-claraio.json', function(object) {
object.scale.multiplyScalar(5);
scene.add(object);
});
json靜態模型 - Object型別
下面給出兩種資料型別的區別:
Geometry型別
Object型別
2.2、動畫
var js_loader = new THREE.JSONLoader(manager);
js_loader.load('./models/body/climb.js', function(geometry, materials) {
for(var i = 0; i < materials.length; i++) {
materials[i].skinning = true;
}
var material = new THREE.MultiMaterial(materials);
var mesh = new THREE.SkinnedMesh(geometry, material); // 劃重點啊!!!
var mixer = new THREE.AnimationMixer(mesh);
mixer.clipAction(geometry.animations[0]).play();
mixers.push(mixer);
mesh.scale.multiplyScalar(.05);
mesh.lookAt(new THREE.Vector3(0, 0, 0));
scene.add(mesh);
}, onProgress, onError);
json動畫
說到json格式動畫,一把辛酸淚(╥﹏╥)。從動畫製作到maya匯出,再到網頁載入,無不有坑。
1、由於不瞭解three.js的資料需求,動畫製作方用maya外掛advancedSkeleton進行綁骨,導致動畫可以展示,資料卻匯出不來,只能自掏腰包重做。
製作動畫時,切記要做成能匯出fbx格式的。
2、用maya做動畫,雖然官方有提供maya轉three.js的外掛,不過匯出資料時,還是碰到了不少問題。
maya2016用官方外掛報錯 “IOError: file C:\Program Files\Autodesk\Maya2016\bin\python27.zip\shutil.py line 82: 2”,Maya 匯出動畫到THREE.js 的博主給出修改後的外掛,親測可以使用。然而還是不可避免地掉了坑。
Maya匯出動畫到THREE.js(補充) 對修改後的外掛進行了總結,其中隱藏網格和報錯 “More than 4 influences on a vertex in xxx” 的問題我這邊也遇到了。
當然,以上兩個bug最直接有效的解決辦法是,在做動畫時就讓設計師刪除隱藏網格並匯出可用的fbx檔案。
3、json動畫載入網頁時,報錯 “THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.”,google了好久才查出,是因為自己建立的不是骨骼蒙皮網格物件(程式碼劃重點部分)。
從3dMax匯出供threeJS使用的帶動作... 裡 “程式碼中如何載入動態模型” 有具體講解。
3、obj檔案
obj格式檔案不支援動畫資料儲存,只用於靜態模型。
首先需要引入OBJLoader.js外掛,如果紋理貼圖是tga或dds格式的,則還需要另外引入TGALoader.js或DDSLoader.js(紋理貼圖問題同樣適用於其他模型格式)。
var obj_loader = new THREE.OBJLoader(manager);
obj_loader.setPath('./models/mooncake/'); // 設定檔案路徑
自己總結了兩種載入方法。
3.1、外部載入紋理
var tga_loader = new THREE.TGALoader();
var material = new THREE.MeshPhongMaterial({
map: tga_loader.load('./models/mooncake/Diffuse.tga'),
normalMap: tga_loader.load('./models/mooncake/Normal.tga'),
specularMap: tga_loader.load('./models/mooncake/S.tga'),
bumpMap: tga_loader.load('./models/mooncake/Bump.tga')
}); // 存在多個紋理材質,具體引數檢視[官方文件 - MeshPhongMaterial]
obj_loader.load('mooncake.obj', function(group) {
var geometry = group.children[0].geometry;
geometry.attributes.uv2 = geometry.attributes.uv;
geometry.center();
var mesh = new THREE.Mesh(geometry, material);
mesh.scale.multiplyScalar(.1);
scene.add(mesh);
}, onProgress, onError);
obj靜態模型 - 外部載入紋理
3.2、obj+mtl
需要額外引用MTLLoader.js檔案
THREE.Loader.Handlers.add(/\.tga$/i, new THREE.TGALoader()); // 劃重點!
var mtl_loader = new THREE.MTLLoader();
mtl_loader.setPath('./models/mooncake/');
mtl_loader.load('mooncake.mtl', function(materials) {
materials.preload();
obj_loader.setMaterials(materials);
obj_loader.load('mooncake.obj', function(object) {
object.scale.multiplyScalar(.1);
scene.add(object);
}, onProgress, onError);
});
obj靜態模型 - obj+mtl
一開始打算用obj+mtl方法載入obj模型,但由於專案是tga格式貼圖,參考大佬的程式碼,卻怎麼都顯示不了紋理,最後放棄轉而琢磨出第一種方法來。
後來偶然看到THREE.Loader.Handlers.add(/\.tga$/i, new THREE.TGALoader());
這句程式碼。經實踐,果然能載入某些不常用格式的紋理材質。
2018.07.13更新
在1、fbx檔案
→1.2、動畫
→解決方案
中新增加了fbx低版本轉高版本的方法。
樓主大大,你的座標丟失的問題,目前解決了嗎?遇到同樣的問題了
用fbx_converter_2013把舊版本的fbx轉成可支援的fbx檔案,我目前是這樣做的