注:本文章內(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);
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);
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)丟失馏段,目前還在尋找原因及解決辦法轩拨。
(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的方法,所以不需要額外引用插件。
現(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);
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);
});
下面給出兩種數(shù)據(jù)類型的區(qū)別:
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);
說到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叮阅、外部載入紋理
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);
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+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更新
以上就是自己總結(jié)的一些經(jīng)驗(yàn)幕垦,歡迎小伙伴留言討論ε=ε=(ノ≧?≦)ノ