層級模型節點命名、查找、遍歷
本文是Three.js電子書的6.2節
上節課說過Threejs場景對象Scene和各種子對象構成的層級模型就是一個樹結構。如果你有一定的算法基礎對樹結構肯定會非常瞭解,如果你瞭解前端的DOM樹結構也非常有助於本節課的學習,如果這些都不瞭解也沒有關係,直接體驗本節課的案例源碼。
本文通過Three.js的一個類Group
來介紹Threejs層級模型的概念,如果你對WebGL層級模型已經有一定的概念,直接把重點放在Group
的瞭解上,如果沒有層級模型的概念,就藉着對Three.js APIGroup
的介紹瞭解下該概念。
模型命名(.name
屬性)
在層級模型中可以給一些模型對象通過.name
屬性命名進行標記。
group.add(Mesh)
// 網格模型命名
Mesh.name = "眼睛"
// mesh父對象對象命名
group.name = "頭"
樹結構層級模型
實際開發的時候,可能會加載外部的模型,然後從模型對象通過節點的名稱.name
查找某個子對象,爲了大家更容易理解,本節課不加載外部模型,直接通過代碼創建一個非常簡易的機器人模型,然後在機器人基礎上進行相關操作。
// 頭部網格模型和組
var headMesh = sphereMesh(10, 0, 0, 0);
headMesh.name = "腦殼"
var leftEyeMesh = sphereMesh(1, 8, 5, 4);
leftEyeMesh.name = "左眼"
var rightEyeMesh = sphereMesh(1, 8, 5, -4);
rightEyeMesh.name = "右眼"
var headGroup = new THREE.Group();
headGroup.name = "頭部"
headGroup.add(headMesh, leftEyeMesh, rightEyeMesh);
// 身體網格模型和組
var neckMesh = cylinderMesh(3, 10, 0, -15, 0);
neckMesh.name = "脖子"
var bodyMesh = cylinderMesh(14, 30, 0, -35, 0);
bodyMesh.name = "腹部"
var leftLegMesh = cylinderMesh(4, 60, 0, -80, -7);
leftLegMesh.name = "左腿"
var rightLegMesh = cylinderMesh(4, 60, 0, -80, 7);
rightLegMesh.name = "右腿"
var legGroup = new THREE.Group();
legGroup.name = "腿"
legGroup.add(leftLegMesh, rightLegMesh);
var bodyGroup = new THREE.Group();
bodyGroup.name = "身體"
bodyGroup.add(neckMesh, bodyMesh, legGroup);
// 人Group
var personGroup = new THREE.Group();
personGroup.name = "人"
personGroup.add(headGroup, bodyGroup)
personGroup.translateY(50)
scene.add(personGroup);
// 球體網格模型創建函數
function sphereMesh(R, x, y, z) {
var geometry = new THREE.SphereGeometry(R, 25, 25); //球體幾何體
var material = new THREE.MeshPhongMaterial({
color: 0x0000ff
}); //材質對象Material
var mesh = new THREE.Mesh(geometry, material); // 創建網格模型對象
mesh.position.set(x, y, z);
return mesh;
}
// 圓柱體網格模型創建函數
function cylinderMesh(R, h, x, y, z) {
var geometry = new THREE.CylinderGeometry(R, R, h, 25, 25); //球體幾何體
var material = new THREE.MeshPhongMaterial({
color: 0x0000ff
}); //材質對象Material
var mesh = new THREE.Mesh(geometry, material); // 創建網格模型對象
mesh.position.set(x, y, z);
return mesh;
}
遞歸遍歷方法.traverse()
Threejs層級模型就是一個樹結構,可以通過遞歸遍歷的算法去遍歷Threejs一個模型對象的所有後代,可以通過下面代碼遞歸遍歷上面創建一個機器人模型或者一個外部加載的三維模型。
上節課說過Threejs場景對象Scene和各種子對象構成的層級模型就是一個樹結構。如果你有一定的算法基礎對樹結構肯定會非常瞭解,如果你瞭解前端的DOM樹結構也非常有助於本節課的學習,如果這些都不瞭解也沒有關係,直接體驗本節課的案例源碼。
本文通過Three.js的一個類`Group`來介紹Threejs層級模型的概念,如果你對WebGL層級模型已經有一定的概念,直接把重點放在`Group`的瞭解上,如果沒有層級模型的概念,就藉着對Three.js API`Group`的介紹瞭解下該概念。
### 模型命名(`.name`屬性)
在層級模型中可以給一些模型對象通過`.name`屬性命名進行標記。
```javascript
group.add(Mesh)
// 網格模型命名
Mesh.name = "眼睛"
// mesh父對象對象命名
group.name = "頭"
樹結構層級模型
實際開發的時候,可能會加載外部的模型,然後從模型對象通過節點的名稱.name
查找某個子對象,爲了大家更容易理解,本節課不加載外部模型,直接通過代碼創建一個非常簡易的機器人模型,然後在機器人基礎上進行相關操作。
// 頭部網格模型和組
var headMesh = sphereMesh(10, 0, 0, 0);
headMesh.name = "腦殼"
var leftEyeMesh = sphereMesh(1, 8, 5, 4);
leftEyeMesh.name = "左眼"
var rightEyeMesh = sphereMesh(1, 8, 5, -4);
rightEyeMesh.name = "右眼"
var headGroup = new THREE.Group();
headGroup.name = "頭部"
headGroup.add(headMesh, leftEyeMesh, rightEyeMesh);
// 身體網格模型和組
var neckMesh = cylinderMesh(3, 10, 0, -15, 0);
neckMesh.name = "脖子"
var bodyMesh = cylinderMesh(14, 30, 0, -35, 0);
bodyMesh.name = "腹部"
var leftLegMesh = cylinderMesh(4, 60, 0, -80, -7);
leftLegMesh.name = "左腿"
var rightLegMesh = cylinderMesh(4, 60, 0, -80, 7);
rightLegMesh.name = "右腿"
var legGroup = new THREE.Group();
legGroup.name = "腿"
legGroup.add(leftLegMesh, rightLegMesh);
var bodyGroup = new THREE.Group();
bodyGroup.name = "身體"
bodyGroup.add(neckMesh, bodyMesh, legGroup);
// 人Group
var personGroup = new THREE.Group();
personGroup.name = "人"
personGroup.add(headGroup, bodyGroup)
personGroup.translateY(50)
scene.add(personGroup);
// 球體網格模型創建函數
function sphereMesh(R, x, y, z) {
var geometry = new THREE.SphereGeometry(R, 25, 25); //球體幾何體
var material = new THREE.MeshPhongMaterial({
color: 0x0000ff
}); //材質對象Material
var mesh = new THREE.Mesh(geometry, material); // 創建網格模型對象
mesh.position.set(x, y, z);
return mesh;
}
// 圓柱體網格模型創建函數
function cylinderMesh(R, h, x, y, z) {
var geometry = new THREE.CylinderGeometry(R, R, h, 25, 25); //球體幾何體
var material = new THREE.MeshPhongMaterial({
color: 0x0000ff
}); //材質對象Material
var mesh = new THREE.Mesh(geometry, material); // 創建網格模型對象
mesh.position.set(x, y, z);
return mesh;
}
遞歸遍歷方法.traverse()
Threejs層級模型就是一個樹結構,可以通過遞歸遍歷的算法去遍歷Threejs一個模型對象的所有後代,可以通過下面代碼遞歸遍歷上面創建一個機器人模型或者一個外部加載的三維模型。
scene.traverse(function(obj) {
if (obj.type === "Group") {
console.log(obj.name);
}
if (obj.type === "Mesh") {
console.log(' ' + obj.name);
obj.material.color.set(0xffff00);
}
if (obj.name === "左眼" | obj.name === "右眼") {
obj.material.color.set(0x000000)
}
// 打印id屬性
console.log(obj.id);
// 打印該對象的父對象
console.log(obj.parent);
// 打印該對象的子對象
console.log(obj.children);
})
查找某個具體的模型
看到Threejs的.getObjectById()
、.getObjectByName()
等方法,如果已有前端基礎,很容易聯想到DOM的一些方法。
Threejs和前端DOM一樣,可以通過一個方法查找樹結構父元素的某個後代對象,對於普通前端而言可以通過name或id等方式查找一個或多個DOM元素,Threejs同樣可以通過一些方法查找一個模型樹中的某個節點。更多的查找方法和方法的使用細節可以查看基類Object3D
// 遍歷查找scene中複合條件的子對象,並返回id對應的對象
var idNode = scene.getObjectById ( 4 );
console.log(idNode);
// 遍歷查找對象的子對象,返回name對應的對象(name是可以重名的,返回第一個)
var nameNode = scene.getObjectByName ( "左腿" );
nameNode.material.color.set(0xff0000);
scene.traverse(function(obj) {
if (obj.type === “Group”) {
console.log(obj.name);
}
if (obj.type === “Mesh”) {
console.log(’ ’ + obj.name);
obj.material.color.set(0xffff00);
}
if (obj.name === “左眼” | obj.name === “右眼”) {
obj.material.color.set(0x000000)
}
// 打印id屬性
console.log(obj.id);
// 打印該對象的父對象
console.log(obj.parent);
// 打印該對象的子對象
console.log(obj.children);
})
### 查找某個具體的模型
看到Threejs的`.getObjectById()`、`.getObjectByName()`等方法,如果已有前端基礎,很容易聯想到DOM的一些方法。
Threejs和前端DOM一樣,可以通過一個方法查找樹結構父元素的某個後代對象,對於普通前端而言可以通過name或id等方式查找一個或多個DOM元素,Threejs同樣可以通過一些方法查找一個模型樹中的某個節點。更多的查找方法和方法的使用細節可以查看基類[Object3D](http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/core/Object3D)
```javascript
// 遍歷查找scene中複合條件的子對象,並返回id對應的對象
var idNode = scene.getObjectById ( 4 );
console.log(idNode);
上節課說過Threejs場景對象Scene和各種子對象構成的層級模型就是一個樹結構。如果你有一定的算法基礎對樹結構肯定會非常瞭解,如果你瞭解前端的DOM樹結構也非常有助於本節課的學習,如果這些都不瞭解也沒有關係,直接體驗本節課的案例源碼。
本文通過Three.js的一個類`Group`來介紹Threejs層級模型的概念,如果你對WebGL層級模型已經有一定的概念,直接把重點放在`Group`的瞭解上,如果沒有層級模型的概念,就藉着對Three.js API`Group`的介紹瞭解下該概念。
### 模型命名(`.name`屬性)
在層級模型中可以給一些模型對象通過`.name`屬性命名進行標記。
```javascript
group.add(Mesh)
// 網格模型命名
Mesh.name = "眼睛"
// mesh父對象對象命名
group.name = "頭"
樹結構層級模型
實際開發的時候,可能會加載外部的模型,然後從模型對象通過節點的名稱.name
查找某個子對象,爲了大家更容易理解,本節課不加載外部模型,直接通過代碼創建一個非常簡易的機器人模型,然後在機器人基礎上進行相關操作。
// 頭部網格模型和組
var headMesh = sphereMesh(10, 0, 0, 0);
headMesh.name = "腦殼"
var leftEyeMesh = sphereMesh(1, 8, 5, 4);
leftEyeMesh.name = "左眼"
var rightEyeMesh = sphereMesh(1, 8, 5, -4);
rightEyeMesh.name = "右眼"
var headGroup = new THREE.Group();
headGroup.name = "頭部"
headGroup.add(headMesh, leftEyeMesh, rightEyeMesh);
// 身體網格模型和組
var neckMesh = cylinderMesh(3, 10, 0, -15, 0);
neckMesh.name = "脖子"
var bodyMesh = cylinderMesh(14, 30, 0, -35, 0);
bodyMesh.name = "腹部"
var leftLegMesh = cylinderMesh(4, 60, 0, -80, -7);
leftLegMesh.name = "左腿"
var rightLegMesh = cylinderMesh(4, 60, 0, -80, 7);
rightLegMesh.name = "右腿"
var legGroup = new THREE.Group();
legGroup.name = "腿"
legGroup.add(leftLegMesh, rightLegMesh);
var bodyGroup = new THREE.Group();
bodyGroup.name = "身體"
bodyGroup.add(neckMesh, bodyMesh, legGroup);
// 人Group
var personGroup = new THREE.Group();
personGroup.name = "人"
personGroup.add(headGroup, bodyGroup)
personGroup.translateY(50)
scene.add(personGroup);
// 球體網格模型創建函數
function sphereMesh(R, x, y, z) {
var geometry = new THREE.SphereGeometry(R, 25, 25); //球體幾何體
var material = new THREE.MeshPhongMaterial({
color: 0x0000ff
}); //材質對象Material
var mesh = new THREE.Mesh(geometry, material); // 創建網格模型對象
mesh.position.set(x, y, z);
return mesh;
}
// 圓柱體網格模型創建函數
function cylinderMesh(R, h, x, y, z) {
var geometry = new THREE.CylinderGeometry(R, R, h, 25, 25); //球體幾何體
var material = new THREE.MeshPhongMaterial({
color: 0x0000ff
}); //材質對象Material
var mesh = new THREE.Mesh(geometry, material); // 創建網格模型對象
mesh.position.set(x, y, z);
return mesh;
}
遞歸遍歷方法.traverse()
Threejs層級模型就是一個樹結構,可以通過遞歸遍歷的算法去遍歷Threejs一個模型對象的所有後代,可以通過下面代碼遞歸遍歷上面創建一個機器人模型或者一個外部加載的三維模型。
scene.traverse(function(obj) {
if (obj.type === "Group") {
console.log(obj.name);
}
if (obj.type === "Mesh") {
console.log(' ' + obj.name);
obj.material.color.set(0xffff00);
}
if (obj.name === "左眼" | obj.name === "右眼") {
obj.material.color.set(0x000000)
}
// 打印id屬性
console.log(obj.id);
// 打印該對象的父對象
console.log(obj.parent);
// 打印該對象的子對象
console.log(obj.children);
})
查找某個具體的模型
看到Threejs的.getObjectById()
、.getObjectByName()
等方法,如果已有前端基礎,很容易聯想到DOM的一些方法。
Threejs和前端DOM一樣,可以通過一個方法查找樹結構父元素的某個後代對象,對於普通前端而言可以通過name或id等方式查找一個或多個DOM元素,Threejs同樣可以通過一些方法查找一個模型樹中的某個節點。更多的查找方法和方法的使用細節可以查看基類Object3D
// 遍歷查找scene中複合條件的子對象,並返回id對應的對象
var idNode = scene.getObjectById ( 4 );
console.log(idNode);
// 遍歷查找對象的子對象,返回name對應的對象(name是可以重名的,返回第一個)
var nameNode = scene.getObjectByName ( "左腿" );
nameNode.material.color.set(0xff0000);
// 遍歷查找對象的子對象,返回name對應的對象(name是可以重名的,返回第一個)
var nameNode = scene.getObjectByName ( “左腿” );
nameNode.material.color.set(0xff0000);