THREE.js中加載不同格式的模型及動畫(fbx冲呢、json和obj)

注:本文章內(nèi)容基于 Three.js 88dev 實(shí)現(xiàn)

作為剛接觸three.js的小萌新舍败,勵志將自己開荒歷程記錄下來,希望對后來人有所幫助敬拓。
網(wǎng)上有很多demo邻薯,文檔卻不多。每次都是乘凸,照搬別人的數(shù)據(jù)沒問題厕诡,換成自己的模型/動畫總會報(bào)錯(cuò)! (╯‵□′)╯︵┻━┻
多次踩坑后营勤,總結(jié)出三種常用格式的加載方法灵嫌。

1、fbx文件

three.js有官方的fbx插件葛作,可以直接將模型加載至網(wǎng)頁寿羞,并且支持動畫數(shù)據(jù),代碼量也是最少的赂蠢。
但是绪穆,該格式存在很大弊端:插件對文件格式的規(guī)范很嚴(yán)格,換言之,插件支持性不太好玖院。從網(wǎng)上下載的fbx動畫菠红,十有八九會加載失敗。

首先需要引入FBXLoader.js插件难菌,如果報(bào)錯(cuò) “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郊酒、靜態(tài)模型

fbx_loader.load('./models/miku/miku.fbx', function(object) {
    object.scale.multiplyScalar(.1);    // 縮放模型大小
    scene.add(object);
}, onProgress, onError);
fbx靜態(tài)模型

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、如果遇到報(bào)錯(cuò) “URIError: URI malformed”猎塞,說明fbx文件格式不符合插件要求试读。可能是fbx版本過低導(dǎo)致的荠耽。

檢測方法:
新版blender導(dǎo)入該fbx文件,如果提示 “Version xxxx unsupported, must be xxxx or later”比藻,說明你的模型文件版本太低铝量。

解決方案有三:
(1)導(dǎo)入3dmax,再重新導(dǎo)出成fbx文件银亲,將低版本轉(zhuǎn)換為最新版本慢叨。經(jīng)實(shí)踐,雖然在3dmax和blender中動畫顯示正常务蝠,但是載入網(wǎng)頁后模型變得支離破碎拍谐。可能是坐標(biāo)丟失馏段,目前還在尋找原因及解決辦法轩拨。

fbx低版本轉(zhuǎn)高版本后,坐標(biāo)丟失

(2)用官方提供的插件將fbx文件轉(zhuǎn)換成json動畫數(shù)據(jù)院喜。
(3)根據(jù) [blender]version 6100 unsupported,must be 7100 or later問題怎么辦 提供的方法亡蓉,可通過FBX_Converter_2013將低版本fbx轉(zhuǎn)換成可支持的fbx文件,親測可用喷舀。

2砍濒、如果遇到報(bào)錯(cuò) “TypeError: Cannot read property 'has' of undefined”,同樣是因?yàn)槟P臀募环弦?guī)范硫麻。

檢測方法:
Chrome Devtools斷點(diǎn)調(diào)試爸邢,你會發(fā)現(xiàn)很多參數(shù)都是undefined。

解決方案:
同上(2)拿愧。

2杠河、json文件

three.js自帶了加載json的方法,所以不需要額外引用插件。

Three.js展示模型問題總結(jié) 中講到:

現(xiàn)在的JSON格式有兩個(gè)類型感猛,一個(gè)是Geometry類型七扰,需要JSONLoader加載;一個(gè)是Object類型陪白,需要ObjectLoader加載颈走。

用錯(cuò)loader.js的話,會報(bào)錯(cuò) “THREE.ObjectLoader: Can't load xxx.json. Use THREE.JSONLoader instead.” 或者 “THREE.JSONLoader: xxx.json should be loaded with THREE.ObjectLoader instead.”咱士。

2.1立由、靜態(tài)模型

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);    // 多個(gè)紋理
    var mesh = new THREE.Mesh(geometry, material);
    mesh.scale.multiplyScalar(.06);
    scene.add(mesh);
}, onProgress, onError);
json靜態(tài)模型 - 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靜態(tài)模型 - Object類型

下面給出兩種數(shù)據(jù)類型的區(qū)別:


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);    // 劃重點(diǎn)啊3诜俊5勒怠!
    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動畫

說到j(luò)son格式動畫文捶,一把辛酸淚(╥﹏╥)荷逞。從動畫制作到maya導(dǎo)出,再到網(wǎng)頁載入粹排,無不有坑种远。

1、由于不了解three.js的數(shù)據(jù)需求顽耳,動畫制作方用maya插件advancedSkeleton進(jìn)行綁骨坠敷,導(dǎo)致動畫可以展示,數(shù)據(jù)卻導(dǎo)出不來射富,只能自掏腰包重做膝迎。
??制作動畫時(shí),切記要做成能導(dǎo)出fbx格式的辉浦。

2弄抬、用maya做動畫,雖然官方有提供maya轉(zhuǎn)three.js的插件宪郊,不過導(dǎo)出數(shù)據(jù)時(shí)掂恕,還是碰到了不少問題。
??maya2016用官方插件報(bào)錯(cuò) “IOError: file C:\Program Files\Autodesk\Maya2016\bin\python27.zip\shutil.py line 82: 2”弛槐,Maya 導(dǎo)出動畫到THREE.js 的博主給出修改后的插件懊亡,親測可以使用。然而還是不可避免地掉了坑乎串。
??Maya導(dǎo)出動畫到THREE.js(補(bǔ)充) 對修改后的插件進(jìn)行了總結(jié)店枣,其中隱藏網(wǎng)格和報(bào)錯(cuò) “More than 4 influences on a vertex in xxx” 的問題我這邊也遇到了。

當(dāng)然,以上兩個(gè)bug最直接有效的解決辦法是鸯两,在做動畫時(shí)就讓設(shè)計(jì)師刪除隱藏網(wǎng)格并導(dǎo)出可用的fbx文件闷旧。

3、json動畫載入網(wǎng)頁時(shí)钧唐,報(bào)錯(cuò) “THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.”忙灼,google了好久才查出,是因?yàn)樽约簞?chuàng)建的不是骨骼蒙皮網(wǎng)格對象(代碼劃重點(diǎn)部分)钝侠。
??從3dMax導(dǎo)出供threeJS使用的帶動作... 里 “代碼中如何加載動態(tài)模型” 有具體講解该园。

3、obj文件

obj格式文件不支持動畫數(shù)據(jù)存儲帅韧,只用于靜態(tài)模型里初。

首先需要引入OBJLoader.js插件,如果紋理貼圖是tga或dds格式的忽舟,則還需要另外引入TGALoader.js或DDSLoader.js(紋理貼圖問題同樣適用于其他模型格式)双妨。

var obj_loader = new THREE.OBJLoader(manager);
obj_loader.setPath('./models/mooncake/');    // 設(shè)置文件路徑

自己總結(jié)了兩種加載方法。

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')
});    // 存在多個(gè)紋理材質(zhì)斥难,具體參數(shù)查看[官方文檔 - 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靜態(tài)模型 - 外部載入紋理

3.2、obj+mtl

需要額外引用MTLLoader.js文件

THREE.Loader.Handlers.add(/\.tga$/i, new THREE.TGALoader());    // 劃重點(diǎn)帘饶!
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靜態(tài)模型 - obj+mtl

一開始打算用obj+mtl方法加載obj模型,但由于項(xiàng)目是tga格式貼圖群扶,參考大佬的代碼及刻,卻怎么都顯示不了紋理,最后放棄轉(zhuǎn)而琢磨出第一種方法來竞阐。
后來偶然看到THREE.Loader.Handlers.add(/\.tga$/i, new THREE.TGALoader());這句代碼缴饭。經(jīng)實(shí)踐,果然能載入某些不常用格式的紋理材質(zhì)骆莹。




2018.07.13更新

1颗搂、fbx文件1.2、動畫解決方案中新增加了fbx低版本轉(zhuǎn)高版本的方法



2019.03.20更新

github項(xiàng)目地址



以上就是自己總結(jié)的一些經(jīng)驗(yàn)幕垦,歡迎小伙伴留言討論ε=ε=(ノ≧?≦)ノ

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末丢氢,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子先改,更是在濱河造成了極大的恐慌疚察,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仇奶,死亡現(xiàn)場離奇詭異貌嫡,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門岛抄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來别惦,“玉大人,你說我怎么就攤上這事夫椭〉УВ” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵益楼,是天一觀的道長猾漫。 經(jīng)常有香客問我,道長感凤,這世上最難降的妖魔是什么悯周? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮陪竿,結(jié)果婚禮上禽翼,老公的妹妹穿的比我還像新娘。我一直安慰自己族跛,他們只是感情好闰挡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著礁哄,像睡著了一般长酗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上桐绒,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天夺脾,我揣著相機(jī)與錄音,去河邊找鬼茉继。 笑死咧叭,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的烁竭。 我是一名探鬼主播菲茬,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼派撕!你這毒婦竟也來了婉弹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤腥刹,失蹤者是張志新(化名)和其女友劉穎马胧,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衔峰,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡佩脊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年蛙粘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片威彰。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡出牧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出歇盼,到底是詐尸還是另有隱情舔痕,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布豹缀,位于F島的核電站伯复,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏邢笙。R本人自食惡果不足惜啸如,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望氮惯。 院中可真熱鬧叮雳,春花似錦、人聲如沸妇汗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽杨箭。三九已至寞焙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間互婿,已是汗流浹背棺弊。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留擒悬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓稻艰,卻偏偏與公主長得像懂牧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子尊勿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫僧凤、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,093評論 4 62
  • 寶的入學(xué)問題已經(jīng)塵埃落定——終于步入了理想的學(xué)校元扔。非常感謝幫助過我的人躯保,內(nèi)心說不出的喜悅,終究為了孩子能澎语,又盡了自...
    lesinlee閱讀 268評論 0 0
  • 回首往事我無言以對 今夜途事,所有影子飛回我身邊 在月光下排著隊(duì)向我討債 時(shí)光這一把梳子 地?cái)偵系牧畠r(jià)貨 在腦海里梳頭...
    子健閱讀 668評論 0 1
  • 首先尸变,我希望標(biāo)題被你當(dāng)做一個(gè)疑問句或是設(shè)問來讀义图,而不是咄咄逼人的反問句。 晚上召烂,坐著校車從一個(gè)校區(qū)回到另一個(gè)校區(qū)碱工,...
    cogitoergo_sum閱讀 490評論 0 3
  • 很多爸爸們在知道了自己在家庭教育中的重要作用之后,也非常想容易其中奏夫,可是他們發(fā)現(xiàn)自己融入不進(jìn)去怕篷。 我曾經(jīng)遇到一位父...
    愛家心理閱讀 485評論 0 1