文章目录
- 简介
- 例子
- 查看组对象
- 组对象相关方法
- add
- remove
- 层级模型节点命名、查找、遍历
- 模型命名
- 例子
- 遍历
- 查找
- 本地坐标与世界坐标
- 例子
- 本地坐标
- 世界坐标
- 缩放系数
专栏目录请点击
简介
层级模型就是一个树的结构,他有一个组的概念,对于组我们可以进行旋转、平移等操作,那么组内的物体也会进行同样的操作,我们可以看下面的例子
例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
body {
margin: 0;
overflow: hidden;
/* 隐藏body窗口区域滚动条 */
}
</style>
<!--引入three.js三维引擎-->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js"></script>
<!-- 引入threejs扩展控件OrbitControls.js -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/controls/OrbitControls.js"></script>
</head>
<body>
<script>
/**
* 创建场景对象Scene
*/
var scene = new THREE.Scene();
//创建两个网格模型mesh1、mesh2
var geometry = new THREE.BoxGeometry(20, 20, 20);
var material = new THREE.MeshLambertMaterial({ color: 0x0000ff });
var mesh1 = new THREE.Mesh(geometry, material);
var mesh2 = new THREE.Mesh(geometry, material);
mesh2.translateX(25);
// 创建组对象
var group = new THREE.Group();
// 添加到组中
group.add(mesh1);
group.add(mesh2);
//把group插入到场景中作为场景子对象
scene.add(group);
// 对于组进行操作
group.translateY(100);
// 坐标系辅助显示
var axesHelper = new THREE.AxesHelper(200);
scene.add(axesHelper);
/**
* 光源设置
*/
//点光源
var point = new THREE.PointLight(0xffffff);
point.position.set(400, 200, 300); //点光源位置
scene.add(point); //点光源添加到场景中
//环境光
var ambient = new THREE.AmbientLight(0x444444);
scene.add(ambient);
/**
* 相机设置
*/
var width = window.innerWidth; //窗口宽度
var height = window.innerHeight; //窗口高度
var k = width / height; //窗口宽高比
var s = 150; //三维场景显示范围控制系数,系数越大,显示的范围越大
//创建相机对象
var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
camera.position.set(200, 300, 200); //设置相机位置
camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
/**
* 创建渲染器对象
*/
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); //设置渲染区域尺寸
renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
// 渲染函数
function render() {
renderer.render(scene, camera); //执行渲染操作
}
render();
//创建控件对象 相机对象camera作为参数 控件可以监听鼠标的变化,改变相机对象的属性
var controls = new THREE.OrbitControls(camera, renderer.domElement);
//监听鼠标事件,触发渲染函数,更新canvas画布渲染效果
controls.addEventListener('change', render);
</script>
</body>
</html>
渲染出来的效果如下
查看组对象
// 查看子对象
console.log(group.children);
当然,我们还可以查看场景的结构
console.log(scene.children);
组对象相关方法
add
group.add(mesh1);
group.add(mesh2);
// 或者
group.add(mesh1,mesh2);
当前的add方式是继承自Object3D
,像场景Secne
、网络模型Mesh
、光源对象Light
的add方法都是继承的
remove
同样remove方法也是继承自Object3D
,他会删除父对象中的一个子对象,如下
group.remove(mesh1);
scene.remove(light,group);
层级模型节点命名、查找、遍历
模型命名
一般我们可以通过name属性进行命名,如下
group.add(Mesh)
// 网格模型命名
Mesh.name = "眼睛"
// mesh父对象对象命名
group.name = "头"
例子
一个简单的机器人模型
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
body {
margin: 0;
overflow: hidden;
/* 隐藏body窗口区域滚动条 */
}
</style>
<!--引入three.js三维引擎-->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js"></script>
<!-- 引入threejs扩展控件OrbitControls.js -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/controls/OrbitControls.js"></script>
</head>
<body>
<script>
/**
* 创建场景对象Scene
*/
var scene = new THREE.Scene();
/**
* 创建网格模型
*/
// 头部网格模型和组
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;
}
// 坐标系辅助显示
var axesHelper = new THREE.AxesHelper(200);
scene.add(axesHelper);
/**
* 光源设置
*/
//点光源
var point = new THREE.PointLight(0xffffff);
point.position.set(400, 200, 300); //点光源位置
scene.add(point); //点光源添加到场景中
//环境光
var ambient = new THREE.AmbientLight(0x444444);
scene.add(ambient);
// console.log(point.id);
// console.log(ambient.id);
/**
* 相机设置
*/
var width = window.innerWidth; //窗口宽度
var height = window.innerHeight; //窗口高度
var k = width / height; //窗口宽高比
var s = 100; //三维场景显示范围控制系数,系数越大,显示的范围越大
//创建相机对象
var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
camera.position.set(200, 300, 200); //设置相机位置
camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
/**
* 创建渲染器对象
*/
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); //设置渲染区域尺寸
// renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
// 渲染函数
function render() {
renderer.render(scene, camera); //执行渲染操作
}
render();
//创建控件对象 相机对象camera作为参数 控件可以监听鼠标的变化,改变相机对象的属性
var controls = new THREE.OrbitControls(camera, renderer.domElement);
//监听鼠标事件,触发渲染函数,更新canvas画布渲染效果
controls.addEventListener('change', render);
</script>
</body>
</html>
渲染出来的结果如下
遍历
我们进行遍历的时候一般使用traverse
方法,也可以遍历外部加载的三维模型
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的方法,关于查找的更多的方法,我们可以查看官网
// 遍历查找对象的子对象,返回name对应的对象(name是可以重名的,返回第一个)
var nameNode = scene.getObjectByName ( "左腿" );
nameNode.material.color.set(0xff0000);
console.log(nameNode);
// 遍历查找对象的子对象,并返回id对应的对象
var idNode = scene.getObjectById ( 4 );
console.log(idNode);
打印如下
本地坐标与世界坐标
例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
body {
margin: 0;
overflow: hidden;
/* 隐藏body窗口区域滚动条 */
}
</style>
<!--引入three.js三维引擎-->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js"></script>
<!-- 引入threejs扩展控件OrbitControls.js -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/controls/OrbitControls.js"></script>
</head>
<body>
<script>
/**
* 创建场景对象Scene
*/
var scene = new THREE.Scene();
/**
* 创建网格模型
*/
var geometry = new THREE.BoxGeometry(20, 20, 20); //创建一个立方体几何对象Geometry
var material = new THREE.MeshLambertMaterial({
color: 0x0000ff
}); //材质对象Material
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
mesh.position.set(50, 0, 0)
var group = new THREE.Group();
group.add(mesh); //网格模型添加到组中
group.position.set(50, 0, 0)
scene.add(group); //组添加到场景中
// 获得世界坐标
//该语句默认在threejs渲染的过程中执行 如果想获得世界矩阵属性、世界位置属性等属性,需要手动更新
scene.updateMatrixWorld(true);
var worldPosition = new THREE.Vector3();
mesh.getWorldPosition(worldPosition)
console.log('世界坐标', worldPosition);
console.log('本地坐标', mesh.position);
// 坐标系辅助显示
var axesHelper = new THREE.AxesHelper(200);
scene.add(axesHelper);
/**
* 光源设置
*/
//点光源
var point = new THREE.PointLight(0xffffff);
point.position.set(400, 200, 300); //点光源位置
scene.add(point); //点光源添加到场景中
//环境光
var ambient = new THREE.AmbientLight(0x444444);
scene.add(ambient);
/**
* 相机设置
*/
var width = window.innerWidth; //窗口宽度
var height = window.innerHeight; //窗口高度
var k = width / height; //窗口宽高比
var s = 150; //三维场景显示范围控制系数,系数越大,显示的范围越大
//创建相机对象
var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
camera.position.set(200, 300, 200); //设置相机位置
camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
/**
* 创建渲染器对象
*/
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); //设置渲染区域尺寸
renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
// 渲染函数
function render() {
renderer.render(scene, camera); //执行渲染操作
}
render();
//创建控件对象 相机对象camera作为参数 控件可以监听鼠标的变化,改变相机对象的属性
var controls = new THREE.OrbitControls(camera, renderer.domElement);
//监听鼠标事件,触发渲染函数,更新canvas画布渲染效果
controls.addEventListener('change', render);
</script>
</body>
</html>
渲染后的效果如下
然后我们看看打印
本地坐标
我们会发现本地坐标是物体自己的设置的坐标,或者说物体相对于父对象设置的坐标,模型对象的position
就是模型的本地坐标
世界坐标
- 我们观察上面的打印,就会发现世界坐标是组的坐标加上模型的本地坐标
- 说白了世界坐标就是以场景建立的坐标系为最终坐标系出现的坐标
缩放系数
缩放属性scale
,也分为局部缩放(本地缩放),通过getWorldScale
可以获取一个模型的世界缩放系数,除此之外,还有本地矩阵materix
和世界矩阵matrixWorld
,都是相同的道理