group.remove(mesh1,mesh2);
Vector3與模型位置、縮放屬性
Group層級模型(樹結構)
創建了兩個網格模型mesh1、mesh2,通過THREE.Group
類創建一個組對象group,然后通過add
方法把網格模型mesh1、mesh2作為設置為組對象group的子對象,然后在通過執行scene.add(group)
把組對象group作為場景對象的scene的子對象。也就是說場景對象是scene是group的父對象,group是mesh1、mesh2的父對象。
//創建兩個網格模型mesh1、mesh2
const geometry = new THREE.BoxGeometry(20, 20, 20);
const material = new THREE.MeshLambertMaterial({color: 0x00ffff});
const group = new THREE.Group();
const mesh1 = new THREE.Mesh(geometry, material);
const mesh2 = new THREE.Mesh(geometry, material);
mesh2.translateX(25);
//把mesh1型插入到組group中,mesh1作為group的子對象
group.add(mesh1);
//把mesh2型插入到組group中,mesh2作為group的子對象
group.add(mesh2);
//把group插入到場景中作為場景子對象
scene.add(group);
查看子對象.children
hreejs場景對象Scene、組對象Group都有一個子對象屬性.children
通過該屬性可以訪問父對象的子對象,子對象屬性.children
的值是數組,所有子對象是數組的值,父對象執行.add()
方法的本質就是把參數中的子對象添加到自身的子對象屬性.children
中。
console.log('查看group的子對象',group.children);
場景對象結構
場景對象Scene的子對象,除了組對象Group
之外,還可以看到環境光AmbientLight
、平行光DirectionalLight
、輔助坐標對象AxesHelper
。
console.log('查看Scene的子對象',scene.children);
場景對象對象scene構成的層級模型本身是一個樹結構,場景對象層級模型的第一層,也就是樹結構的根節點,一般來說網格模型Mesh、點模型Points、線模型Line是樹結構的最外層葉子結點。構建層級模型的中間層一般都是通過Threejs的Group
類來完成,Group
類實例化的對象可以稱為組對象。?
.add()
方法總結
場景對象Scene
、組對象Group
的.add()
方法都是繼承自它們共同的基類(父類)Object3D
group.add(mesh1);
group.add(mesh2);// 或group.add(mesh1,mesh2);
父對象旋轉縮放平移變換,子對象跟著變化
格模型mesh1、mesh2作為設置為父對象group的子對象,如果父對象group進行旋轉、縮放、平移變換,子對象同樣跟著變換。
//沿著Y軸平移mesh1和mesh2的父對象,mesh1和mesh2跟著平移
group.translateY(100);//父對象縮放,子對象跟著縮放
group.scale.set(4,4,4);//父對象旋轉,子對象跟著旋轉
group.rotateY(Math.PI/6)
Object3D
表示模型對象節點
受threejs歷史影響,你會在很多別的代碼中看到Object3D
作為Group
來使用,某種程度上,你可把兩者畫等號,只是Group
更加語義化,Object3D本身就是表示模型節點的意思。
const mesh1 = new THREE.Mesh(geometry, material);
const mesh2 = new THREE.Mesh(geometry, material);
const obj = new THREE.Object3D();//作為mesh1和mesh2的父對象
obj.add(mesh1,mesh2);
mesh也能添加mesh子對象
threejs默認mesh也可以添加子對象,其實原因很簡單,mesh和Group父類都是Object3D,本質上也可以認為都是Object3D。
//threejs默認mesh也可以添加子對象,mesh基類也是Object3D
mesh1.add(mesh2);
遍歷模型樹結構、查詢模型節點
模型命名(.name
屬性)
在層級模型中可以給一些模型對象通過.name
屬性命名進行標記
const group = new THREE.Group();
group.name='小區';
const mesh = new THREE.Mesh(geometry, material);
mesh.name='五號樓';
樹結構層級模型設置.name
屬性
下面是通過代碼創建了一個層級模型,一般實際開發的時候,會加載外部的模型,然后從模型對象通過節點的名稱.name
查找某個子對象。
// 批量創建多個長方體表示高層樓
const group1 = new THREE.Group(); //所有高層樓的父對象
group1.name = "高層";
for (let i = 0; i < 5; i++) {const geometry = new THREE.BoxGeometry(20, 60, 10);const material = new THREE.MeshLambertMaterial({color: 0x00ffff});const mesh = new THREE.Mesh(geometry, material);mesh.position.x = i * 30; // 網格模型mesh沿著x軸方向陣列group1.add(mesh); //添加到組對象group1mesh.name = i + 1 + '號樓';// console.log('mesh.name',mesh.name);
}
group1.position.y = 30;const group2 = new THREE.Group();
group2.name = "洋房";
// 批量創建多個長方體表示洋房
for (let i = 0; i < 5; i++) {const geometry = new THREE.BoxGeometry(20, 30, 10);const material = new THREE.MeshLambertMaterial({color: 0x00ffff});const mesh = new THREE.Mesh(geometry, material);mesh.position.x = i * 30;group2.add(mesh); //添加到組對象group2mesh.name = i + 6 + '號樓';
}
group2.position.z = 50;
group2.position.y = 15;const model = new THREE.Group();
model.name='小區房子';
model.add(group1, group2);
model.position.set(-50,0,-25);
?遞歸遍歷方法.traverse()
Threejs層級模型就是一個樹結構,可以通過遞歸遍歷的算法去遍歷Threejs一個模型對象包含的所有后代。
// 遞歸遍歷model包含所有的模型節點
model.traverse(function(obj) {console.log('所有模型節點的名稱',obj.name);// obj.isMesh:if判斷模型對象obj是不是網格模型'Mesh'if (obj.isMesh) {//判斷條件也可以是obj.type === 'Mesh'obj.material.color.set(0xffff00);}
});
查找某個具體的模型.getObjectByName()
Threejs和前端DOM一樣,可以通過一個方法查找樹結構父元素的某個后代對象,對于普通前端而言可以通過name或id等方式查找一個或多個DOM元素,Threejs同樣可以通過一些方法查找一個模型樹中的某個節點。
// 返回名.name為"4號樓"對應的對象
const nameNode = scene.getObjectByName ("4號樓");
nameNode.material.color.set(0xff0000);
?本地坐標和世界坐標
本地(局部)坐標和世界坐標
mesh的世界坐標就是mesh.position與group.position的累加
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(10, 20, 0);
const group = new THREE.Group();
group.add(mesh);
group.position.set(50, 30, 0);
改變子對象的
.position
,子對象在3D空間中的坐標會發生改變。改變父對象的
.position
,子對象在3D空間中的位置也會跟著變化,也就是說父對象.position
和子對象.position
疊加才是才是子對象的.position
。
任何一個模型的本地坐標(局部坐標)就是模型的.position
屬性。
一個模型的世界坐標,說的是,模型自身.position
和所有父對象.position
累加的坐標。
.getWorldPosition()
獲取世界坐標
mesh.getWorldPosition(Vector3)
讀取一個模型的世界坐標,并把讀取結果存儲到參數Vector3
中。
// 聲明一個三維向量用來表示某個坐標
const worldPosition = new THREE.Vector3();
// 獲取mesh的世界坐標,你會發現mesh的世界坐標受到父對象group的.position影響
mesh.getWorldPosition(worldPosition);
console.log('世界坐標',worldPosition);
console.log('本地坐標',mesh.position);
給子對象添加一個局部坐標系
mesh.add(坐標系)
給mesh添加一個局部坐標系。
//可視化mesh的局部坐標系
const meshAxesHelper = new THREE.AxesHelper(50);
mesh.add(meshAxesHelper);
改變模型相對局部坐標原點位置
通過改變幾何體頂點坐標,可以改變模型自身相對坐標原點的位置。
//長方體的幾何中心默認與本地坐標原點重合
const geometry = new THREE.BoxGeometry(50, 50, 50);// 平移幾何體的頂點坐標,改變幾何體自身相對局部坐標原點的位置
geometry.translate(50/2,0,0,);;
旋轉測試
局部坐標相對模型發生改變,旋轉軸自然也會發生變化。
// .rotateY()默認繞幾何體中心旋轉,經過上面幾何體平移變化,你會發現.rotateY()是繞長方體面上一條線旋轉
mesh.rotateY(Math.PI/3);//
function render() {model.rotateY(0.01);//旋轉動畫requestAnimationFrame(render);
}
render();
移除對象.remove()
.remove()
方法和.add()
方法是相反的,是把子對象從父對象的.children()
屬性中刪除。
查看父類Object3D的移除方法.remove()
場景對象Scene
、組對象Group
、網格模型對象Mesh
的.remove()
方法都是繼承自它們共同的基類(父類)Object3D
。
.remove()
方法使用
.add()
方法是給父對象添加一個子對象,.remove()
方法是刪除父對象中的一個子對象。
// 刪除父對象group的子對象網格模型mesh1
group.remove(mesh1);scene.remove(ambient);//移除場景中環境光
scene.remove(model);//移除場景中模型對象
一次移除多個子對象
group.remove(mesh1,mesh2);
模型隱藏或顯示
開發web3d項目,有時候需要臨時隱藏一個模型,或者一個模型處于隱藏狀態,需要重新恢復顯示。
模型屬性.visible
模型對象的父類Object3D
封裝了一個屬性.visible
,通過該屬性可以隱藏或顯示一個模型。
mesh.visible =false;// 隱藏一個網格模型,visible的默認值是true
group.visible =false;// 隱藏一個包含多個模型的組對象groupmesh.visible =true;// 使網格模型mesh處于顯示狀態
?材質屬性.visible
材質對象的父類Material
封裝了一個.visible
屬性,通過該屬性可以控制是否隱藏該材質對應的模型對象。
// 隱藏網格模型mesh,visible的默認值是true
mesh.material.visible =false;
// 注意如果mesh2和mesh的.material屬性指向同一個材質,mesh2也會跟著mesh隱藏