本章主要学习知识点
- 了解三维向量概念,并实现使用向量归一化移动模型
- 了解欧拉对象
- 练习修改材质的颜色
- 掌握如何复制克隆模型
三维向量Vector3
三维向量Vector3
有xyz三个分量,threejs中会用三维向量Vector3
表示很多种数据,想象你去快递站取件,需要三个关键信息: 楼层、房间号、货架位置,
在three.js中用代码表示
js
const position = new THREE.Vector3(3,4,10)
这里的(3,5,10)对应为包裹位于 3楼、4号房间,第10个货架
如果要用来描述物体位置则为
js
mesh.position.set(x,y,z)
三维向量的实际应用
思考一个问题,假设我们需要前往一个目标地,那该如何描述怎么前往呢?通常会以实际的距离来进行表达,如
向东走100米,在向北走30米,再向西走300米
这就是一个三维方向向量
,用代码表示
js
const direction = new THREE.Vector3(100,30,300)
我们可以让物体沿该向量所指方向移动
js
mesh.position.add(direction)
三维向量数学运算
三维向量支持常见数学操作,就像用工具测量空间关系
操作类型 | 生活类比 | Three.js 方法示例 |
---|---|---|
加法 | 两段路程叠加 | v1.add(v2) |
减法 | 计算两个地点的间距 | v1.sub(v2); v1.length() |
缩放 | 按比例放大/缩小距离 | v1.multiplyScalar(0.5) |
单位化 | 提取纯方向(忽略长度) | v1.normalize() |
向量归一化
创建一个立方体,并设置模型平移旋转缩放
js
// 设置模型位置
cube.position.set(1,0,0)
// 设置平移
cube.translateY(3)
// 缩放
cube.scale.set(2,2,2)
// 旋转
cube.rotateX(45)
cube.rotateY(45)
cube.rotateZ(45)
模型当前的状态

设置三维向量(1,1,1),并通过使用normalize()
单位化向量,也就是向量归一化,并设置立方体沿该向量所指方向移动5个单位

欧拉Euler与角度
欧拉使用来描述物体绕三个轴XYZ的旋转角度,想象我们在操作无人机时有三个控制杆:
俯仰角Pitch
: 前后倾斜(类似点头)→对应绕X轴旋转偏航角Yaw
: 左右转向(类似摇头)→对应绕Y轴旋转滚转角Roll
: 侧身翻转(类似翻跟头)→对应绕Z轴旋转
在Three.js 中,用THREE.Euler(x,y,z,order)
表示这三个旋转角度
js
// 创建一个Euler对象,参数为弧度值,分别表示绕x轴、y轴、z轴的旋转角度,旋转顺序为xyz
const Euler = new THREE.Euler(Math.PI/4, 0, Math.PI/2,'XYZ')
旋转顺序
旋转顺序就像做菜的步骤顺序不同会影响最终味道:
- 顺序XYZ:先调俯仰→再调方向→最后侧翻
- 顺序ZYX:先侧翻→再调方向→最后调俯仰
在实际开发中需要注意,同一组角度(30°,45°,0°)
,不同顺序会导致物体朝向完全不同的方向
使用欧拉角度旋转时存在的问题,万向锁
万向锁;旋转bug
当俯仰角达到90度时,偏航和滚转轴会重合,导致失去一个旋转自由度。这就好比使用手机指南针时,若手机完全竖直(俯仰90度),左右旋转和前后倾斜会变得难以区分
面对这种问题,three.js中提供了 四元数用来避免万向锁问题的出现,目前只需要了解欧拉就好了
设置模型在Y轴上的角度,并使其沿X轴和Y轴旋转看看
js
cube.rotation.y = Math.PI/4;
cube.rotation.y += 0.01;
cube.rotation.x += 0.01;
// 渲染场景和相机
renderer.render( scene, camera );
requestAnimationFrame( animation );

模型材质颜色
材质颜色的两种类型
整体材质颜色
- 通过材质对象的
.color
属性设置(如material.color = new THREE.Color('red')
),类似给物体涂上统一颜色的油漆 - 不受顶点颜色影响,适合单一颜色的物体(如纯色塑料玩具)
- 通过材质对象的
顶点颜色
- 给几何体每个顶点单独设置颜色(如
geometry.colors.push(new THREE.Color('blue'))
),类似用彩色马克笔给模型的不同部位上色 - 常常用于温度云图、渐变效果等需要局部变色的场景
- 给几何体每个顶点单独设置颜色(如
敲黑板,重点哈,材质类型对颜色的影响
- 基础材质(MeshBasicMaterial)
- 最简单的材质,颜色不受光照影响
- 场景:白炽灯下的彩色纸片,始终保持固定颜色
- 高光材质(MeshPhongMaterial)
- 颜色会随光照角度变化,产生镜面反光
- 通过
.specular
设置高光颜色,类似金属表面反光效果 - 场景:阳光下旋转的金属水杯,会有亮斑移动
- 物理材质(MeshStandardMaterial)
- 通过
roughness
(粗糙度)和metalness
(金属感)参数精细控制颜色表现 - 场景:粗糙的铁锈表面 vs 光滑的不锈钢表面
- 通过
光照对颜色的影响
- 环境光:均匀染色(如阴天时的整体色调)
- 平行光:产生明暗分界(如正午阳光下的物体投影)
- 点光源:形成渐变光晕(如灯泡周围的亮度衰减)
修改材质颜色
js
// 兰伯特材质
const material = new THREE.MeshLambertMaterial({color: 'deepskyblue'})
// 修改材质颜色
material.color.set('deeppink')
材质颜色将被改为deeppink深红粉

克隆和复制
克隆和复制两者的核心区别在于操作对象的状态和引用关系,我简单的对比下
克隆 clone
- 行为 :像复印机一样,生成一个独立的新对象,内容和原对象完全相同。
- 特性 :新对象与原对象无引用关联(除非共享子属性,如材质和几何体)。
复制 copy
- 行为 :像用模板覆盖白纸,将原对象属性值赋给已存在的目标对象,目标对象原有数据被替换。
- 特性 :操作后,目标对象与原对象无关联。
创建一个立方体,尝试克隆一个相同的立方体
js
const material = new THREE.MeshLambertMaterial({color: 'deepskyblue'})
// 网格模型
cube = new THREE.Mesh( geometry, material );
// 克隆
cube2 = cube.clone();
cube2.position.x = 5;

我们克隆出了一个与原立方体一摸一样的立方体,那如何知道克隆出来的立方体与原立方体是无引用关联的呢?我们可以设置原立方体旋转
js
cube.rotation.y += 0.01;

可以看到新的模型并未旋转,我们尝试修改原立方体的材质颜色,看看新立方体是否共享了材质
js
cube.material.color.set('deeppink')

嗯,如上图,新立方体的材质颜色也同步更新了,所以在使用克隆时,共享子属性是有引用关联的这点要注意
接下来尝试复制原立方体的旋转动作,看看结果如何
js
cube2.rotation.copy(cube.rotation)

两者皆以同样的节奏旋转起来了
一些值得注意的细节
- 克隆几何体Geometry: 生成完全独立的几何体数据,修改原几何体不影响克隆体。
- 克隆网格模型Mesh
- 默认克隆: 新模型与原模型共享几何体和材质。修改原模型的材质颜色,克隆体也会变化
- 完全独立克隆:需额外克隆几何体和材质
js
const mesh2 = mesh.clone();
mesh2.geometry = mesh.geometry.clone(); // 独立几何体
mesh2.material = mesh.material.clone(); // 独立材质
以上案例均可在案例中心查看体验
