1. 程式人生 > >【three.js : 3D】【loader】THREE.js中載入不同格式的模型及動畫(fbx、json和obj)

【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、外部載入紋理

官方文件 - MeshPhongMaterial

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檔案,我目前是這樣做的