一、三维向量Vector3与模型位置、缩放属性
位置属性.position
执行.translateX()、.translateY()等方法本质上改变的都是模型的位置属性.position。
javascript
// 位置属性.position使用threejs三维向量对象Vector3表示的
console.log("模型位置属性.position的值", mesh.position);
//new THREE.Vector3()实例化一个三维向量对象
const v3 = new THREE.Vector3(0, 0, 0);
console.log("v3", v3);
v3.set(10, 0, 0); //set方法设置向量的值
v3.x = 100; //访问x、y或z属性改变某个分量的值
// .position的值是Vector3,意味着你想改变.position,可以查询文档Vector3类
// 直接设置网格模型的位置
mesh.position.set(100, 100, 100);
mesh.position.x = 100; //设置模型的x坐标
// 网格模型沿着x轴方向平移100,
mesh.translateX(100);
属性.scale表示模型对象的xyz三个方向上的缩放比例,.scale的属性值是一个三维向量对象Vector3,默认值是THREE.Vector3(1.0,1.0,1.0)。
javascript
mesh.scale.y = 3; //y方向放大3倍
// 网格模型xyz方向分别缩放0.5,1.5,2倍
mesh.scale.set(0.5, 1.5, 2);

二、欧拉Euler与角度属性.rotation
javascript
// 角度属性.rotation使用threejs欧拉对象Euler表示的
console.log('模型角度属性.rotation的值', mesh.rotation);
// 创建一个欧拉对象,表示绕着x、y、z轴分别旋转45度,0度,90度
// const Euler = new THREE.Euler( Math.PI/4,0, Math.PI/2);
const Euler = new THREE.Euler();
// 通过xyz分量属性定义和参数一样
Euler.x = Math.PI/4;
Euler.y = 0;
Euler.z = Math.PI/2;
角度属性.rotation的值是欧拉对象Euler,意味着你想改变属性.rotation
javascript
//绕y轴的角度设置为60度
mesh.rotation.y = Math.PI/3;
//绕y轴的角度增加60度
mesh.rotation.y += Math.PI/3;
//绕y轴的角度减去60度
mesh.rotation.y -= Math.PI/3;

模型执行.rotateX()、.rotateY()等旋转方法,改变了模型的角度属性.rotation
javascript
// 通过模型的旋转方法,也可以改变角度属性.rotation
mesh.rotateY(Math.PI / 3);// 绕着Y轴旋转60度


三、模型材质颜色(Color对象)
javascript
const material = new THREE.MeshLambertMaterial({
color: 0xffff00,
});
const mesh = new THREE.Mesh(geometry, material);
// 浏览器控制台查看材质颜色属性的属性值
console.log('material.color',material.color);

颜色对象
javascript
// 创建一个颜色对象
const color = new THREE.Color();//默认是纯白色0xffffff。
console.log('查看颜色对象结构',color);//可以查看rgb的值

通过.r、.g、.b属性改变颜色值
javascript
color.r = 0.0;
color.b = 0.0;
Color提供了.setHex()、.setRGB()、.setStyle()、.set()等修改颜色值的方法
javascript
color.setRGB(0,1,0);//RGB方式设置颜色
color.setHex(0x00ff00);//十六进制方式设置颜色
color.setStyle('#00ff00');//前端CSS颜色值设置颜色
重置模型材质的颜色
javascript
// 十六进制颜色
material.color.set(0x00ff00);
// 前端CSS风格颜色值:'#00ff00'、'rgb(0,255,0)'等形式
// material.color.set('#00ff00');
// material.color.set('rgb(0,255,0)');
四、模型材质父类Material
javascript
material.transparent = true;//开启透明
material.opacity = 0.5;//设置透明度
// material.side = THREE.BackSide;//背面可以看到
material.side = THREE.DoubleSide;//双面可见
五、模型材质和几何体属性
javascript
console.log('mesh',mesh);
console.log('mesh.geometry',mesh.geometry);
console.log('mesh.material',mesh.material);

javascript
// 访问模型材质,并设置材质的颜色属性
mesh.material.color.set(0xffff00);
// 访问模型几何体,并平移几何体顶点数据
mesh.geometry.translate(0,100,0);

mesh共享材质或几何体
javascript
const mesh2 = new THREE.Mesh(geometry, material);
mesh2.position.x = 100;
// 两个mesh共享一个材质,改变一个mesh的颜色,另一个mesh2的颜色也会跟着改变
// mesh.material和mesh2.material都指向同一个material
// 三者等价:mesh.material、mesh2.material、material
mesh.material.color.set(0xffff00);
// 三者等价:mesh.geometry、mesh2.geometry、geometry
mesh.geometry.translate(0,100,0);
export {mesh,mesh2};

六、克隆.clone()和复制.copy()
克隆.clone()简单说就是复制一个和原对象一样的新对象
javascript
const v1 = new THREE.Vector3(1, 2, 3);
console.log('v1',v1);
//v2是一个新的Vector3对象,和v1的.x、.y、.z属性值一样
const v2 = v1.clone();
console.log('v2',v2);

复制.copy()简单说就是把一个对象属性的属性值赋值给另一个对象
javascript
const v3 = new THREE.Vector3(4, 5, 6);
//读取v1.x、v1.y、v1.z的赋值给v3.x、v3.y、v3.z
v3.copy(v1);

Mesh克隆
javascript
const material = new THREE.MeshLambertMaterial({
color: 0xffffff,
});
const mesh = new THREE.Mesh(geometry, material);
// 通过mesh克隆.clone()一个和mesh一样的新模型对象mesh2
const mesh2 = mesh.clone();
mesh2.position.x = 100;
// 通过克隆.clone()获得的新模型和原来的模型共享材质和几何体
//改变材质颜色,或者说改变mesh2颜色,mesh和mesh2颜色都会改变
// material.color.set(0xffff00);
mesh2.material.color.set(0xffff00);
// 改变mesh的位置,使之位于mesh2的正上方(y),距离100。
mesh.position.copy(mesh2.position); //1. 第1步位置重合
mesh.position.y += 100; //1. 第2步mesh在原来y的基础上增加100

javascript
// 克隆几何体和材质,重新设置mesh2的材质和几何体属性
mesh2.geometry = mesh.geometry.clone();
mesh2.material = mesh.material.clone();
// 改变mesh2颜色,不会改变mesh的颜色
mesh2.material.color.set(0xff0000);

Threejs (4)
一、组对象Group、层级模型
javascript
//创建两个网格模型mesh1、mesh2
const geometry = new THREE.BoxGeometry(20, 20, 20);
const material = new THREE.MeshLambertMaterial({ color: 0xffffff });
// 创建一个组对象
const group = new THREE.Group();
const mesh1 = new THREE.Mesh(geometry, material);
const mesh2 = new THREE.Mesh(geometry, material);
mesh2.translateX(25);
插入到组中
javascript
//把mesh1型插入到组group中,mesh1作为group的子对象
group.add(mesh1);
//把mesh2型插入到组group中,mesh2作为group的子对象
group.add(mesh2);
// group.add(mesh1, mesh2);
父对象旋转缩放平移变换,子对象跟着变化
javascript
//沿着Y轴平移mesh1和mesh2的父对象,mesh1和mesh2跟着平移
group.translateY(100);
//父对象缩放,子对象跟着缩放
group.scale.set(4, 4, 4);
//父对象旋转,子对象跟着旋转
group.rotateY(Math.PI / 6);
javascript
// group也会作为场景scene的子对象插入到场景中
export default group;

查看子对象.children
javascript
console.log('查看group的子对象',group.children);

查看Scene的子对象
javascript
console.log('查看Scene的子对象',scene.children);

Object3D作为Group来使用,Group更加语义化,Object3D本身就是表示模型节点的意思

mesh也能添加mesh子对象
javascript
//threejs默认mesh也可以添加子对象,mesh基类也是Object3D
mesh1.add(mesh2);
高层楼、洋房
javascript
// 引入three.js
import * as THREE from 'three';
// 创建一个层级模型对象
// 批量创建多个长方体表示高层楼
const group1 = new THREE.Group(); //所有高层楼的父对象
for (let i = 0; i < 5; i++) {
const geometry = new THREE.BoxGeometry(20, 60, 10);
const material = new THREE.MeshLambertMaterial({
color: 0xffffff
});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.x = i * 30; // 网格模型mesh沿着x轴方向阵列
group1.add(mesh); //添加到组对象group1
}
// 平移父对象group1,所有子对象跟着平移
group1.position.y = 30;
// 旋转父对象group1,所有子对象跟着旋转
// group1.rotateY(Math.PI/2);
const group2 = new THREE.Group();
// 批量创建多个长方体表示洋房
for (let i = 0; i < 5; i++) {
const geometry = new THREE.BoxGeometry(20, 30, 10);
const material = new THREE.MeshLambertMaterial({
color: 0xffffff
});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.x = i * 30;
group2.add(mesh); //添加到组对象group2
}
group2.position.z = 50;
group2.position.y = 15;
const model = new THREE.Group();
model.add(group1, group2);
// 整体平移model里面的所有模型对象
model.position.set(-50,0,-25);
export default model;

二、递归遍历模型树结构、查询模型节点
模型命名(.name属性)
javascript
// 批量创建多个长方体表示高层楼
const group1 = new THREE.Group(); //所有高层楼的父对象
group1.name = "高层";

javascript
const mesh = new THREE.Mesh(geometry, material);
mesh.position.x = i * 30;
group2.add(mesh); //添加到组对象group2
mesh.name = i + 6 + "号楼";
javascript
// 批量创建多个长方体表示高层楼
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: 0xffffff,
});
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: 0xffffff,
});
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()
javascript
// 递归遍历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);
}
});

查找某个具体的模型.getObjectByName()
javascript
// .getObjectByName()根据名字选择模型节点
const mesh = model.getObjectByName("2号楼");
mesh.material.color.set(0xff0000);

三、本地坐标和世界坐标
javascript
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(50, 0, 0);
const group = new THREE.Group();
group.add(mesh); //网格模型添加到组中
group.position.set(50, 0, 0);
任何一个模型的本地坐标 (局部坐标 )就是模型的.position属性。
javascript
// 声明一个三维向量用来表示某个坐标
const worldPosition = new THREE.Vector3();
// 获取mesh的世界坐标,你会发现mesh的世界坐标受到父对象group的.position影响
mesh.getWorldPosition(worldPosition)
console.log('世界坐标',worldPosition);
console.log('本地坐标',mesh.position);

.getWorldPosition()获取世界坐标
给模型添加一个可视化的局部坐标系
javascript
//可视化mesh的局部坐标系
const meshAxesHelper = new THREE.AxesHelper(50);
mesh.add(meshAxesHelper);

四、改变模型相对局部坐标原点位置
javascript
model.rotateY(0.01);//旋转动画

javascript
// 平移几何体的顶点坐标,改变几何体自身相对局部坐标原点的位置
geometry.translate(50/2,0,0,);

javascript
// .rotateY()默认绕几何体中心旋转,经过上面几何体平移变化,你会发现.rotateY()是绕长方体面上一条线旋转
mesh.rotateY(Math.PI/3);

五、移除对象.remove()
javascript
//把mesh1型插入到组group中,mesh1作为group的子对象
group.add(mesh1);
//把mesh2型插入到组group中,mesh2作为group的子对象
group.add(mesh2);

remove
javascript
// 删除父对象group的子对象网格模型mesh1
group.remove(mesh1);
// 通过`.remove()`方法删除父对象的子对象之后,可以通过浏览器控制台查看`.children()`属性的变化。
console.log('查看group的子对象',group.children);

javascript
group.remove(mesh1,mesh2);//一次移除多个子对象

六、模型隐藏或显示
模型属性.visible
javascript
mesh.visible =false;// 隐藏一个网格模型,visible的默认值是true

javascript
group.visible =false;// 隐藏一个包含多个模型的组对象group

材质属性.visible
material.visible可以控制是否隐藏该材质对应的模型对象。
如果多个模型引用了同一个材质,如果该材质`.visible`设置为false,意味着隐藏绑定该材质的所有模型。
javascript
mesh1.material.visible =false;
