提示:本系列文章参考http://www.webgl3d.cn/Three.js/的three.js教程。
前言
本篇主要介绍层级模型通过父对象group完成、函数的使用和世界坐标。
一、函数
我们在一个实例里可能多次使用一个几何体,如果一直声明显得很麻烦,我们可以创建一个函数 function 函数名(参数1, 参数2, …) {},在函数里声明几何体、设置材质对象和创建模型对象等,然后直接调用该函数即可。
1.球体网格模型创建函数
下面是函数sphereMesh(R, x, y, z)可以创建球体网格模型,R表示半径,x、y、z表示坐标,需要使用球体网格模型是直接调用该函数即可。如var headMesh = sphereMesh(10, 0, 0, 0);表示坐标(0,0,0)创建半径为10的球体网格模型。
给不同的球体网格模型添加name方便进行区分和调用。如headMesh.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 = "右眼"
// 球体网格模型创建函数
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;
}
2.圆柱体网格模型创建函数
和上面的球体网格模型创建函数思路一样,圆柱比球的参数除了半径R还多了一个高h。
// 身体网格模型和组
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 = "右腿"
// 圆柱体网格模型创建函数
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;
}
二、用类Group实现层级模型
前面学习了创建一个个几何体,现在我们需要将这些子类几何体组装成一个大的父类模型,比如两个球体代表眼睛和一个大的球体组成一个头,使用THREE.Group()方法进行层级模型,可以一直叠加层级,比如球体的头、圆柱体的脖子、圆柱体的身体和四肢构成了一个简易的机器人模型,这是更高级的层。
下面是先通过 var headGroup = new THREE.Group(); 声明一个父对象头部headGroup。
然后通过 headGroup.add(headMesh, leftEyeMesh, rightEyeMesh); 将头的球体模型headMesh和两个眼睛的球体模型leftEyeMesh, rightEyeMesh加入父对象头部headGroup中。
同理父对象身体bodyGroup,通过 bodyGroup.add(neckMesh, bodyMesh, legGroup); 将子对象加入到父对象中。
最后声明父对象人group,通过personGroup.add(headGroup, bodyGroup);将子对象headGroup, bodyGroup加入到父对象中。
最后不要忘记将personGroup加入到场景中。scene.add(personGroup);
// 头部网格模型和组
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);
三、本地坐标.position 和世界坐标 .getWorldPosition() 方法
子对象直接通过 模型变量名.position 获得本地坐标。世界坐标通过 模型变量名.getWorldPosition(世界坐标变量名) 方法获得。
// 声明一个三维向量用来保存世界坐标
var worldPosition = new THREE.Vector3();
// 执行getWorldPosition方法把模型的世界坐标保存到参数worldPosition中
mesh.getWorldPosition(worldPosition);
console.log('世界坐标',worldPosition);
注意如果有父对象group,则世界坐标是模型子对象位置属性.position和mesh父对象group位置属性.position的累加。如模型子对象和父对象group坐标都是(10,0,0),世界坐标应该是两个累加,即(20,0,0)。