Three.js(十四)—— 模型文件加载
文章目錄
- 14、Three.js 加載外部模型文件
-
- 14.1 Three.js 數據結構、導入導出
-
- Threejs導出模型信息
- 自定義模型加載器文件
- 加載Three.js導出的模型數據
- 14.2 加載 stl 文件并解析
-
- stl文件數據結構
- 通過STLLoader.js加載.stl文件
- 使用點模型渲染STL文件
- 14.3 加載obj文件(幾何體、材質、貼圖)
-
- 只加載obj文件
- 同時加載obj文件和mtl文件
- obj包含多個網格模型
- 模型紋理貼圖
- 導出.obj和.mtl的名稱、路徑問題
- .obj文件不包含信息
- 14.4 加載FBX并解析骨骼動畫
-
- 加載器FBXLoader.js
- 加載fbx模型文件
- 查看FBX模型幀動畫數據
- 解析fbx模型骨骼動畫
- 14.5 手鐲在線預覽
-
- 設置紋理貼圖
- 切換顏色
- 14.6 心臟預覽(法線、高光、環境貼圖)
-
- 心臟次時代模型加載設置
14、Three.js 加載外部模型文件
實際開發中,大多數項目,通常是3D美術設計師或建筑、機械等行業工程師提供的由3dmx、blender、substence、Solidworks等軟件創建好的三維模型文件。
本章節第一小節以Threejs引擎自身為例,講解Threejs模型導入導出,該小節對Threejs模型文件本身進行了講解,讓你明白你加載的三維模型文件里面都是包含什么內容。其它章節展示了一些加載外部不同格式模型的案例,除了講解實現代碼外,還對模型的數據結構進行了簡單講解,盡管加載一個模型不一定需要知道它的內容結構,但是如果你理解模型本質上就是頂點、材質等數據,那么隨意給你一種格式模型,你至少會有了解該模型能夠包含哪些數據的意識。
14.1 Three.js 數據結構、導入導出
Threejs導出模型信息
你可以通過下面代碼導出模型的各類信息,然后在瀏覽器控制臺打印出來模型數據,然后復制瀏覽器控制臺模型數據粘貼到json文件中,最后可以嘗試加載解析這些Threejs導出的json文件。之所以這么做,是為了讓你理解其它三維軟件,比如3dmax、blender軟件導出的三維模型文件本質上是什么。
查看Threejs文檔Geometry、Material、Light、Object3D等類,你可以發現這些類都提供了一個方法.toJSON()通過這個方法可以導出Threejs三維模型的各類數據,該方法的功能就是把Threejs的幾何體、材質、光源等對象轉化為JSON格式導出。
導出幾何體信息。
var geometry = new THREE.BoxGeometry(100, 100, 100);
// 控制臺查看立方體數據
console.log(geometry);
// 控制臺查看geometry.toJSON()結果
console.log(geometry.toJSON());
// JSON對象轉化為字符串
console.log(JSON.stringify(geometry.toJSON()));
// JSON.stringify()方法內部會自動調用參數的toJSON()方法
console.log(JSON.stringify(geometry));
導出材質信息。
var material = new THREE.MeshLambertMaterial({color: 0x0000ff,
}); //材質對象Material
console.log(material);
console.log(material.toJSON());
console.log(JSON.stringify(material));
導出場景scene信息。
var mesh = new THREE.Mesh(geometry, material); //網格模型對象Mesh
scene.add(mesh); //網格模型添加到場景中
console.log(scene);
console.log(scene.toJSON());
自定義模型加載器文件
實際開發中,加載一種特定格式的模型文件,Threejs在three.js-master\examples\js\loaders目錄下會提供一系列的加載器,這些加載器本質上都是解析模型文件的字符串,通過正則表達式提取相關的頂點、材質等信息轉化為Threejs自身的類表示的對象。為了讓大家更理解這些常見的加載器,課件中提供了一個源碼案例,編寫了一個非常非常簡易的自定義加載器,然后使用自定義的加載器去加載一個文件,讓大家明白這些加載器怎么來的。
// 如果編寫通用的材質加載器需要枚舉所有的材質,這里沒有列舉完
var typeAPI = {MeshLambertMaterial: THREE.MeshLambertMaterial,MeshBasicMaterial: THREE.MeshBasicMaterial,MeshPhongMaterial: THREE.MeshPhongMaterial,PointsMaterial: THREE.PointsMaterial,
}
// 創建一個文件加載器,該加載器是對異步加載的封裝
var loader = new THREE.FileLoader();
loader.load('material.json', function(elem) {console.log(elem);// 查看加載返回的內容var obj = JSON.parse(elem);// 字符串轉JSON對象console.log(obj);// 查看轉化結果var geometry = new THREE.BoxGeometry(100, 100, 100);/*** 解析材質數據*/// 根據type的值判斷調用threejs的哪一個APIvar material = new typeAPI[obj.type]();// 從obj.color中提取顏色// 16711935對應顏色0xFF00FF 255對應顏色0x0000FFmaterial.color.r = (obj.color >> 16 & 255) / 255; //獲取顏色值R部分material.color.g = (obj.color >> 8 & 255) / 255; //獲取顏色值G部分material.color.b = (obj.color & 255) / 255; //獲取顏色值B部分var mesh = new THREE.Mesh(geometry, material); //網格模型對象Meshscene.add(mesh); //網格模型添加到場景中
})
加載Three.js導出的模型數據
緩沖幾何體數據加載器。
/****/
var loader = new THREE.BufferGeometryLoader();
loader.load('bufferGeometry.json',function (geometry) {// 控制臺查看加載放回的threejs對象結構console.log(geometry);var material = new THREE.MeshLambertMaterial({color: 0x0000ff,}); //材質對象Materialvar mesh = new THREE.Mesh(geometry, material); //網格模型對象Meshscene.add(mesh); //網格模型添加到場景中
})
網格模型Mesh加載,包含幾何體Geometry和材質Material
var loader = new THREE.ObjectLoader();
loader.load('model.json',function (obj) {console.log(obj);
console.log(obj.type);obj.scale.set(100,100,100)scene.add(obj)
})
加載組Group對象,模型對象構成的樹結構
loader.load('group.json', function(obj) {console.log(obj);console.log(obj.type);scene.add(obj)
})
加載場景對象,場景對象不僅包含模型,還包括光源對象
loader.load('scene.json',function (obj) {console.log(obj);console.log(obj.type);obj.scale.set(100,100,100)scene.add(obj)
})
14.2 加載 stl 文件并解析
基本所有的三維軟件都支持導出.stl格式的三維模型文件,.stl格式的三維模型不包含材質Material信息,只包含幾何體頂點數據的信息,你可以簡單地把stl文件理解為幾何體對象Geometry,本節課素材box.STL是一個立方體, 你可以用記事本或代碼編輯器打開文件box.STL查看stl的數據結構。
stl文件數據結構
.stl文件格式的數據結構,對于大多數普通開發者來說,如果僅僅為了加載顯示一個三維模型,也沒必要掌握,這里之所以要強調,不是為了讓你記住,而是為了從底層了解Threejs模型加載的原理,達到舉一反三的目的
三個位置坐標和一個三角形面的法線方向向量是一組數據,這一組數據表示一個三角形面的信息,可以回憶下第二章關于三角形面Face3的講解。
表示一個三角形面信息的一組數據
//三角面1facet normal 0 0 -1 //三角形面法向量outer loopvertex 50 50 -50 //頂點位置vertex 50 -50 -50 //頂點位置vertex -50 50 -50 //頂點位置endloopendfacet
一個立方體有6個矩形平面,每個矩形平面至少需要兩個三角形拼接而成。那么立方體6個矩形平面至少需要12個三角形面構成,你可以查看文件box.STL中的12個三角形信息。
solid box //文件名字
//三角面1facet normal 0 0 -1 //三角形面法向量outer loopvertex 50 50 -50 //頂點位置vertex 50 -50 -50 //頂點位置vertex -50 50 -50 //頂點位置endloopendfacet
//三角面2facet normal 0 0 -1 //三角形面法向量outer loopvertex -50 50 -50 //頂點位置vertex 50 -50 -50 //頂點位置vertex -50 -50 -50 //頂點位置endloopendfacetfacet normal 0 1 0..........
//三角面12facet normal -1 0 0outer loopvertex -50 -50 -50vertex -50 50 50vertex -50 50 -50endloopendfacet
endsolid
通過STLLoader.js加載.stl文件
如果你想通過Threejs加載.stl格式三維模型文件,可以使用Threejs提供的一個擴展庫stl加載器STLLoader.js,你可以在Three.js-master包中找到STLLoader.js文件,具體路徑是three.js-master\examples\js\loaders.
.html文件中引入Threejs的擴展庫STLLoader.js,引入該文件后,就可以在代碼中使用構造函數THREE.STLLoader()實例化一個加載器。
<!--引入STLLoader.js文件-->
<script src="STLLoader.js"></script>
通過構造函數THREE.STLLoader()可以把.stl文件中幾何體頂點信息提取出來轉化為Three.js自身格式的幾何體對象BufferGeometry。如果你有興趣可以閱讀STLLoader.js源碼,尤其是你想獨立開發自己公司特定格式加載器的情況下,更有必要參照學習。
// THREE.STLLoader創建一個加載器
var loader = new THREE.STLLoader();
loader.load('立方體.stl',function (geometry) {// 加載完成后會返回一個幾何體對象BufferGeometry,你可以通過Mesh、Points等方式渲染該幾何體
})
/*** stl數據加載*/
var loader = new THREE.STLLoader();
// 立方體默認尺寸長寬高各200
loader.load('立方體.stl',function (geometry) {// 控制臺查看加載放回的threejs對象結構console.log(geometry);// 查看頂點數,一個立方體6個矩形面,每個矩形面至少2個三角面,每個三角面3個頂點,// 如果沒有索引index復用頂點,就是說一個立方體至少36個頂點console.log(geometry.attributes.position.count);// 縮放幾何體// geometry.scale(0.5,0.5,0.5);// 幾何體居中// geometry.center();// 平移立方體// geometry.translate(-50,-50,-50);var material = new THREE.MeshLambertMaterial({color: 0x0000ff,}); //材質對象Materialvar mesh = new THREE.Mesh(geometry, material); //網格模型對象Meshscene.add(mesh); //網格模型添加到場景中
})
使用點模型渲染STL文件
你可以使用下面代碼代替上面代碼,查看Three.js如果通過點模型Points渲染stl文件中的頂點數據。
/*** 點渲染模式*/loader.load('離心葉輪.stl',function (geometry) {var material = new THREE.PointsMaterial({color: 0x000000,size: 0.5//點對象像素尺寸}); //材質對象var points = new THREE.Points(geometry, material); //點模型對象scene.add(points); //點對象添加到場景中})
14.3 加載obj文件(幾何體、材質、貼圖)
使用三維軟件導出.obj模型文件的時候,會同時導出一個材質文件.mtl, .obj和.stl文件包含的信息一樣都是幾何體頂點相關數據,材質文件.mtl包含的是模型的材質信息,比如顏色、貼圖路徑等。
加載.obj三維模型的時候,可以只加載.obj文件,然后借助three.js引擎自定義材質Material,也可以同時加載.obj和.mtl文件。
只加載obj文件
只加載obj文件,引入路徑three.js-master/examples/js/loaders/OBJLoader.js下的OBJLoader.js文件即可
<!-- 引入obj模型加載庫OBJLoader.js -->
<script src="../../three.js-master/examples/js/loaders/OBJLoader.js"></script>
文件加載
/*** OBJ文件加載 只加載obj文件中的幾何信息,不加載材質文件.mtl*/
var loader = new THREE.OBJLoader();
// 沒有材質文件,系統自動設置Phong網格材質
loader.load('./立方體/box.obj',function (obj) {// 控制臺查看返回結構:包含一個網格模型Mesh的組Groupconsole.log(obj);// 查看加載器生成的材質對象:MeshPhongMaterialconsole.log(obj.children[0].material);scene.add(obj);
})
加載文件返回的對象插入場景中后,你也可以做一些自定的設置,比如縮放、居中等操作。
// 加載后的一些編輯操作
obj.children[0].scale.set(20,20,20);//網格模型縮放
obj.children[0].geometry.center();//網格模型的幾何體居中
obj.children[0].material.color.set(0xff0000);//設置材質顏色
同時加載obj文件和mtl文件
mtl文件包含了模型的材質信息,比如模型顏色、透明度等信息,還有紋理貼圖的路徑,比如顏色貼圖、法線貼圖、高光貼圖等等。
<!-- 引入obj模型加載庫OBJLoader.js -->
<script src="../../three.js-master/examples/js/loaders/OBJLoader.js"></script>
<!-- 引入obj模型材質加載庫MTLLoader.js -->
<script src="../../three.js-master/examples/js/loaders/MTLLoader.js"></script>
/*** OBJ和材質文件mtl加載*/
var OBJLoader = new THREE.OBJLoader();//obj加載器
var MTLLoader = new THREE.MTLLoader();//材質文件加載器
MTLLoader.load('./立方體/box.mtl', function(materials) {// 返回一個包含材質的對象MaterialCreatorconsole.log(materials);//obj的模型會和MaterialCreator包含的材質對應起來OBJLoader.setMaterials(materials);OBJLoader.load('./立方體/box.obj', function(obj) {console.log(obj);obj.scale.set(10, 10, 10); //放大obj組對象scene.add(obj);//返回的組對象插入場景中})
})
obj包含多個網格模型
obj文件可以包含多個網格模型對象,不一定就是一個,這些網格模型對象全部是并列關系,無法通過父子關系構建一個樹結構層級模型。
// 沒有材質文件,系統自動設置Phong網格材質
OBJLoader.load('./多個模型/model.obj',function (obj) {// 控制臺查看返回結構:包含一個網格模型Mesh的組Groupconsole.log(obj);scene.add(obj);// 加載后的一些編輯操作obj.scale.set(20,20,20);//網格模型縮放// 設置其中一個網格模型的顏色obj.children[0].material.color.set(0xff0000);
})
模型紋理貼圖
obj模型的mtl文件可能包含紋理貼圖,也可能不包含,這主要看3D美術是否設置。
一個包含紋理貼圖路徑的.mtl文件,如果路徑有問題,可能會無法加載,可以仿照該案例修改。
// 一個包含紋理貼圖路徑的.mtl文件
newmtl material_1Ns 32d 1Tr 0Tf 1 1 1illum 2Ka 0.5880 0.5880 0.5880Kd 0.9880 0.9880 0.9880Ks 0.1200 0.1200 0.1200map_Kd ./貼圖/Earth.pngmap_ks ./貼圖/EarthSpec.pngnorm ./貼圖/EarthNormal.png
mtl和threejs貼圖對應關系
| mtl貼圖 | Threejs貼圖 |
|---|---|
| map_kd | map |
| map_ks | specularMap |
| map_bump/bump | bumpMap |
/*** OBJ和材質文件mtl加載*/
var OBJLoader = new THREE.OBJLoader(); //obj加載器
var MTLLoader = new THREE.MTLLoader(); //材質文件加載器
MTLLoader.load('./貼圖/material.mtl', function(materials) {// 返回一個包含材質的對象MaterialCreatorconsole.log(materials);//obj的模型會和MaterialCreator包含的材質對應起來OBJLoader.setMaterials(materials);OBJLoader.load('./貼圖/model.obj', function(obj) {console.log(obj);scene.add(obj); //返回的組對象插入場景中// 加載后操作obj.children[0].scale.set(2, 2, 2); //縮放球體網格模型// 通過調節參數,地球表面的凹凸感更強obj.children[0].material.normalScale.set(3, 3);})
})
導出.obj和.mtl的名稱、路徑問題
3dmax導出的obj和mtl模型文件有時候需要修改一下個別位置字符,比如.obj中.mtl文件的名稱可能是亂碼mtllib �����.mtl,.mtl文件中貼圖的路徑要設置正確,比如導出的是絕對路徑還是相對路徑,可以打開看下。
.obj文件不包含信息
.obj文件不包含場景的相機Camera、光源Light等信息,不能導出骨骼動畫、變形動畫,如果希望導出光照信息、相機信息、骨骼動畫信息、變形動畫信息,可以選擇.fbx、.gltf等格式。
14.4 加載FBX并解析骨骼動畫
加載器FBXLoader.js
引入FBX加載器相關文件
<!-- 引入fbx模型加載庫FBXLoader -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/loaders/FBXLoader.js"></script>
<!-- 輔助文件 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/libs/inflate.min.js"></script>
加載fbx模型文件
加載模型文件,加載完成后,如果模型顯示位置不符合要求,可以讓3D美術修改,也可以通過Threejs程序進行平移、縮放等操作。
var loader = new THREE.FBXLoader();//創建一個FBX加載器
loader.load("SambaDancing.fbx", function(obj) {// console.log(obj);//查看加載后返回的模型對象scene.add(obj)// 適當平移fbx模型位置obj.translateY(-80);
})
查看FBX模型幀動畫數據
stl、obj都是靜態模型,不可以包含動畫,fbx除了包含幾何、材質信息,可以存儲骨骼動畫等數據。
解析之前可以先在瀏覽器控制臺查看動畫相關的數據是如何存儲的。你可以看到obj.animations屬性的數組包含兩個剪輯對象AnimationClip,obj.animations[0]對應剪輯對象AnimationClip包含多組關鍵幀KeyframeTrack數據,obj.animations[1]對應的剪輯對象AnimationClip沒有關鍵幀數據,也就是說沒有關鍵幀動畫。具體的開發中,可能美術提供的模型有很多包含關鍵幀動畫的剪輯對象AnimationClip,你可以根據自己的需要解析某個剪輯對象AnimationClip對應的動畫。
var loader = new THREE.FBXLoader();//創建一個FBX加載器
loader.load("SambaDancing.fbx", function(obj) {...// 可以在控制臺打印obj對象,找到animations屬性console.log(obj)// 查看動畫數據 2個剪輯對象AnimationClip,一個有關鍵幀動畫,一個沒有console.log(obj.animations)})
解析fbx模型骨骼動畫
var mixer=null;//聲明一個混合器變量
var loader = new THREE.FBXLoader();//創建一個FBX加載器
loader.load("SambaDancing.fbx", function(obj) {// console.log(obj)scene.add(obj)obj.translateY(-80);// obj作為參數創建一個混合器,解析播放obj及其子對象包含的動畫數據mixer = new THREE.AnimationMixer(obj);// 查看動畫數據console.log(obj.animations)// obj.animations[0]:獲得剪輯對象clipvar AnimationAction=mixer.clipAction(obj.animations[0]);// AnimationAction.timeScale = 1; //默認1,可以調節播放速度// AnimationAction.loop = THREE.LoopOnce; //不循環播放// AnimationAction.clampWhenFinished=true;//暫停在最后一幀播放的狀態AnimationAction.play();//播放動畫
})
// 創建一個時鐘對象Clock
var clock = new THREE.Clock();
// 渲染函數
function render() {renderer.render(scene, camera); //執行渲染操作requestAnimationFrame(render); //請求再次執行渲染函數render,渲染下一幀if (mixer !== null) {//clock.getDelta()方法獲得兩幀的時間間隔// 更新混合器相關的時間mixer.update(clock.getDelta());}
}
render();
14.5 手鐲在線預覽
在線預覽產品的時候,一個產品可能會提供不同的系列,比如顏色不同、造型款式不同。本節課的玉鐲案例模型提供了三種顏色款式,不同的顏色款式本質上就是網格模型的顏色貼圖.map不同。
設置紋理貼圖
model.obj文件中已經包含紋理映射的UV坐標數據,直接給模型顏色貼圖屬性.map賦值即可。
/*** OBJ文件加載 只加載obj文件中的幾何信息,不加載材質文件.mtl*/
var loader = new THREE.OBJLoader();
loader.load('./model.obj',function (obj) {// 控制臺查看返回結構:包含一個網格模型Mesh的組Group// console.log(obj);//加載紋理貼圖texture1.pngvar texture = new THREE.TextureLoader().load('texture1.png');// 顏色貼圖中已經包含了光照信息,所以直接使用不受光照影響的基礎網格材質MeshBasicMaterialobj.children[0].material= new THREE.MeshBasicMaterial({map:texture,//設置顏色紋理貼圖})scene.add(obj);obj.children[0].scale.set(5,5,5);//網格模型縮放
})
切換顏色
模型提供了texture1.png、texture2.png和texture3.png三張貼圖,上面代碼加載了texture1.png作為顏色貼圖。
你可以在上面代碼.load()回調函數中插入下面語句,給玉鐲設置其它的顏色款式。
// 更換紋理貼圖
var texture = new THREE.TextureLoader().load('texture2.png');
obj.children[0].material.map=texture
實際開發的時候,可能會通過前端UI進行顏色交互(顏色交互體驗),其實實現也比較簡單,比如一個按鈕表示綠色,前端代碼只要給該按鈕綁定一個函數,函數中執行代碼mesh.material.map=Texture改變顏色貼圖屬性.map的值即可。不過本節課主要是講解Threejs,關于前端交互內容就不做過多描述,你可以自己創建一個按鈕測試這個思路。
14.6 心臟預覽(法線、高光、環境貼圖)
加載一個心臟的次時代模型,模型包含顏色貼圖.map、法線貼圖.normalMap、高光貼圖.specularMap、環境貼圖.envMap,關于這些貼圖的相關屬性可以查看高光網格模型材質的文檔MeshPhongMaterial。
心臟次時代模型加載設置
/*** OBJ文件加載 只加載obj文件中的幾何信息,不加載材質文件.mtl*/
var loader = new THREE.OBJLoader();
// 沒有材質文件,系統自動設置Phong網格材質
var mesh = null; //聲明一個網格模型變量
loader.load('./heart/model.obj', function(obj) {// 控制臺查看返回結構:包含一個網格模型Mesh的組Groupconsole.log(obj);scene.add(obj);mesh = obj.children[0]; //獲得心臟網格模型mesh.scale.set(10, 10, 10); //網格模型縮放// 創建一個紋理加載器var textureLoader = new THREE.TextureLoader();
...
})
設置模型的顏色貼圖.map。
//加載顏色紋理var texture = textureLoader.load('./heart/color.png');mesh.material.map = texture;
設置模型的法線貼圖.normalMap,表面細節更豐富,為了壓縮模型頂點數量,也就是降低文件大小,3D美術通常會給程序員提供法線貼圖。
var textureNormal = textureLoader.load('./heart/normal.png');
mesh.material.normalMap = textureNormal
// 設置深淺程度
mesh.material.normalScale.set(1.5, 1.5)
對于心臟模型而言,模型外表面不同區域的粗糙度不同,對光線的鏡面反射程度不同,所以可以把這些不同區域的不同光反射信息記錄在一個貼圖上,即高光貼圖.specularMap,設置高光貼圖需要高光網格模型材質MeshPhongMaterial。
// 設置高光貼圖,一個網格模型不同的區域反射光線的能力不同
var textureSpecular = textureLoader.load('./heart/Specular.png');
mesh.material.specularMap = textureSpecular;
mesh.material.specular.set(0xffffff);// 高光反射顏色
mesh.material.shininess = 100;// 高光高亮程度,默認30
通過類CubeTextureLoader來加載六張紋理貼圖’px.jpg’, ‘nx.jpg’, ‘py.jpg’, ‘ny.jpg’, ‘pz.jpg’, ‘nz.jpg’。
設置環境貼圖.envMap,反射周圍環境效果,渲染更逼真。
var textureCube = new THREE.CubeTextureLoader().setPath('環境貼圖/').load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']);
mesh.material.envMap = textureCube;
渲染模型的時候,合理的設置光源是很必要的,比如光源強度太低,模型就會比較灰暗,光源強度太高,模型會過于明亮。
/*** 光源設置*/
//點光源
var point = new THREE.PointLight(0xffffff, 0.3);
point.position.set(400, 200, 300); //點光源位置
scene.add(point); //點光源添加到場景中
// 環境光
var ambient = new THREE.AmbientLight(0xffffff, 0.8);
scene.add(ambient);
// 方向光1
var directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(400, 200, 300);
scene.add(directionalLight);
// 方向光2
var directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(-400, -200, -300);
scene.add(directionalLight);
總結
以上是生活随笔為你收集整理的Three.js(十四)—— 模型文件加载的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: P3700 [CQOI2017]小Q的表
- 下一篇: Convolution(2021牛客暑期