Appearance
上篇文章我们学习了分组概念,我们可以用来模拟一个小区的房子效果。
首先我们的模型都是支持命名的,代码如下
js
const group = new THREE.Group();
group.name='小区房子';
const mesh = new THREE.Mesh(geometry, material);
mesh.name='一号楼';我们实现这么一个效果

js
// 批量创建多个长方体表示高层楼
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); //添加到组对象group1
mesh.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); //添加到组对象group2
mesh.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一个模型对象包含的所有后代。
js
// 递归遍历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);
}
});那如果我想某一栋楼改变下颜色呢
看到Object3D的.getObjectByName()方法 Threejs和前端DOM一样,可以通过一个方法查找树结构父元素的某个后代对象,对于普通前端而言可以通过name或id等方式查找一个或多个DOM元素,Threejs同样可以通过一些方法查找一个模型树中的某个节点。更多的查找方法和方法的使用细节可以查看基类Object3D。
js
// 返回名.name为"4号楼"对应的对象
const nameNode = model.getObjectByName ("4号楼");
nameNode.material.color.set(0xff0000);完整代码
js
import * as THREE from 'three';
import { onMounted } from 'vue';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { useRoute } from 'vue-router';
const route = useRoute();
onMounted(() => {
// 批量创建多个长方体表示高层楼
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); //添加到组对象group1
mesh.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); //添加到组对象group2
mesh.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);
if (route.query.type === '1' || route.query.type === '2') {
// 递归遍历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);
}
});
}
if (route.query.type === '2') {
// 返回名.name为"4号楼"对应的对象
const nameNode = model.getObjectByName('4号楼');
nameNode.material.color.set(0xff0000);
}
// 创建场景
const scene = new THREE.Scene();
scene.add(model); //网格模型添加到场景中
//辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(100);
scene.add(axesHelper);
//光源设置
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(100, 60, 50);
scene.add(directionalLight);
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);
// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
const width = window.innerWidth; //宽度
const height = window.innerHeight; //高度
/**
* 透视投影相机设置
*/
// 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000:远裁截面
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
camera.position.set(292, 223, 185); //相机在Three.js三维坐标系中的位置
camera.lookAt(0, 0, 0); //相机观察目标指向Three.js坐标系原点
/**
* 创建渲染器对象
*/
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
document.getElementById('canvas').appendChild(renderer.domElement);
// 渲染循环
function render() {
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
const controls = new OrbitControls(camera, renderer.domElement);
// 画布跟随窗口变化
window.onresize = function () {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
};
});