前言:在场景中层级模型、网格模型等,就像是多个零件就需要多个网格模型。其实一个层级模型就像一本书的目录一样。层级模型结构如下:
层级模型与在生活中物体当然有关系,比如说一个人身体,头、眼睛、手、腿都是人类的一部分;牛肉、西红柿、生菜都是汉堡包制作好的一部分。
1.组对象(group)
首先创建两个网格模型mesh1和mesh2.通过创建一个组对象group,然后通过add方法把网格模型mesh1、mesh2作为设置为组对象group的子对象,然后在通过执行scene.add(group)把组对象group作为场景对象的scene的子对象。也就是说场景对象scene是group的父对象,group是mesh1、mesh2的父对象,这样就构成了一个三层的层级结构。
javascript
/ 网格模型Mesh
var geometry = new BoxGeometry(100, 100, 100);
// 三角形面渲染模式
var meterial = new MeshLambertMaterial({
color: 0xff0000, //三角面颜色
});
//材质对象
var group = new Group();
//创建组
var mesh1 = new Mesh(geometry, meterial);
var mesh2 = new Mesh(geometry, meterial);
// 第二个网格模型沿着X轴平移 mesh2.translateX(200);
// 把mesh1型插入到组group中,mesh1作为group的子对象
group.add(mesh1);
//把mesh2型插入到组group中,mesh2作为group的子对象
group.add(mesh2);
//把group插入到场景中作为场景子对象
scene.add(group);
效果图:
剩下,需要mesh1和mesh2的父对象调整位置。
通过沿着平移mesh1和mesh2的父对象,mesh1和mesh2跟着平移。
javascript
group.translateY(100);
父对象缩放,子对象跟着缩放。
javascript
group.scale.set(4,4,4);
父对象旋转,子对象跟着旋转。
javascript
group.rotateY(Math.PI/6);
2.查看子对象.children
Threejs场景对象scene、组对象group都是有一个子对象属性.children。其实.children的类型返回是数组。
javascript
console.log('查看group的子对象',group.children)
3.处理场景对象结构
一般来说网格模型mesh、点模型points、线模型line是树结构的最外层叶子结点。构建层级模型的中间层一般都是通过Threejs的group类来完成,group类实例化的对象可以称为组对象。
3.1 add()方法
.add()方法是给父对象添加一个子对象。
还包括场景对象scene、组对象group、网格模型对象mesh、光源对象light等都是继承它们的基类。
可以单独插入一个对象,也可以插入多个对象。
javascript
group.add(mesh1); group.add(mesh2);
//或者
group.add(mesh1,mesh2);
3.2 remove()方法
.remove()方法是删除父对象中的一个子对象。
javascript
// 删除父对象group的子对象网格模型mesh1
group.add(mesh1)
// 一次删除场景中多个对象
scene.remove(light,group)
4.设置模型命名(.name属性)
在层级模型中可以给一些模型对象通过.name属性命名进行标记。
javascript
group.add(Mesh)
// 网格模型命名
mesh.name = "眼睛"
// mesh父对象对象命名
group.name = "头"
5.树结构层级模型
例题:
可以直接通过代码创建一个非常简易的机器人模型。
javascript
// 头部网格模型和组
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 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 Group();
legGroup.name = "腿"
legGroup.add(leftLegMesh, rightEyeMesh);
var bodyGroup = new Group();
bodyGroup.name = "身体"
bodyGroup.add(neckMesh, bodyMesh, legGroup);
// 人,组合成为人类
var personGroup = new Group();
personGroup.name = "人"
personGroup.add(headGroup, bodyGroup);
personGroup.translateY(50)
scene.add(personGroup);
// 球体网格模型创建函数
function sphereMesh(R, x, y, z) {
var geometry = new SphereGeometry(R, 25, 25); //球体几何体
var material = new MeshPhongMaterial({
color: 0x0000ff
}); //材质对象Material
var mesh = new Mesh(geometry, material); // 创建网格模型对象
mesh.position.set(x, y, z);
return mesh;
}
// 圆柱体网格模型创建函数
function cylinderMesh(R, h, x, y, z) { var geometry = new CylinderGeometry(R, R, h, 25, 25); //球体几何体 var material = new MeshPhongMaterial({
color: 0x0000ff
}); //材质对象Material
var mesh = new Mesh(geometry, material); // 创建网格模型对象 mesh.position.set(x, y, z);
return mesh;
}
人体里有多个结构,头部作为网格模型,脑壳、眼睛和耳朵等作为组对象;身体作为网格模型,脖子、左腿和右腿作为组对象等。最后把多个结构称为人类。
效果图:
5.处理递归遍历方法.traverse()
threejs层级模型就是一个树结构,可以通过递归遍历的算法去遍历threejs一个模型对象的所有后代。
javascript
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);
})
6.查找某个具体的模型
看到Threejs的.getObjectById()、.getObjectByName()等方法。Threejs和前端DOM一样,可以通过一个方法查找树结构父元素的某个后代对象,对于普通前端而言可以通过name或id等方式查找一个或多个DOM元素,Threejs同样可以通过一些方法查找一个模型树中的某个节点。
javascript
// 遍历查找scene中复合条件的子对象,并返回id对应的对象
var idNode = scene.getObjectById ( 4 );
console.log(idNode);
遍历查找对象的子对象,返回name对应的对象(name是可以重名的,返回第一个)。
javascript
var nameNode = scene.getObjectByName ( "左腿" );
nameNode.material.color.set(0xff0000);