# three.js-study
**Repository Path**: hyy-study/three.js-study
## Basic Information
- **Project Name**: three.js-study
- **Description**: Three.js 学习Demo
- **Primary Language**: JavaScript
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 4
- **Forks**: 0
- **Created**: 2022-08-02
- **Last Updated**: 2025-09-25
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
### 参照:http://www.yanhuangxueyuan.com/
### 个人感觉光看郭隆邦老师的Three.js电子书没有实感,所以就将每个实例敲了一下,并使其可以运行直接查看。

# 快速入门
## 第一个Three.js案例
麻雀虽小,五脏俱全,整体展示了Three.js的整套渲染系统。
```javascript
第一个three.js文件_WebGL三维场景
```
## 旋转动画、requestAnimationFrame
均匀旋转
```javascript
let T0 = new Date();//上次时间
function render() {
let T1 = new Date();//本次时间
let t = T1-T0;//时间差
T0 = T1;//把本次时间赋值给上次时间
requestAnimationFrame(render);
renderer.render(scene,camera);//执行渲染操作
mesh.rotateY(0.001*t);//旋转角速度0.001弧度每毫秒
}
render();
```
## 鼠标操作三维场景旋转缩放
- 缩放:滚动—鼠标中键
- 旋转:拖动—鼠标左键
- 平移:拖动—鼠标右键
注意开发中不要同时使用requestAnimationFrame()或controls.addEventListener('change', render)调用同一个函数,这样会冲突。
```javascript
function render() {
renderer.render(scene,camera);//执行渲染操作
// mesh.rotateY(0.01);//每次绕y轴旋转0.01弧度
requestAnimationFrame(render);//请求再次执行渲染函数render
}
render();
var controls = new THREE.OrbitControls(camera,renderer.domElement);//创建控件对象
// 已经通过requestAnimationFrame(render);周期性执行render函数,没必要再通过监听鼠标事件执行render函数
// controls.addEventListener('change', render)
```
## 不同几何体
```javascript
//长方体 参数:长,宽,高
var geometry = new THREE.BoxGeometry(100, 100, 100);
// 球体 参数:半径60 经纬度细分数40,40
var geometry = new THREE.SphereGeometry(60, 40, 40);
// 圆柱 参数:圆柱面顶部、底部直径50,50 高度100 圆周分段数
var geometry = new THREE.CylinderGeometry( 50, 50, 100, 25 );
// 正八面体
var geometry = new THREE.OctahedronGeometry(50);
// 正十二面体
var geometry = new THREE.DodecahedronGeometry(50);
// 正二十面体
var geometry = new THREE.IcosahedronGeometry(50);
```
## 辅助三维坐标系AxisHelper
```javascript
// 辅助坐标系 参数250表示坐标系大小,可以根据场景大小去设置
var axisHelper = new THREE.AxisHelper(250);
scene.add(axisHelper);
```
## 不同材质
### 材质类型
| 材质类型 | 功能 |
| --- | --- |
| [MeshBasicMaterial](http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/materials/MeshBasicMaterial) | 基础网格材质,不受光照影响的材质 |
| [MeshLambertMaterial](http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/materials/MeshLambertMaterial) | Lambert网格材质,与光照有反应,漫反射 |
| [MeshPhongMaterial](http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/materials/MeshPhongMaterial) | 高光Phong材质,与光照有反应 |
| [MeshStandardMaterial](http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/materials/MeshStandardMaterial) | PBR物理材质,相比较高光Phong材质可以更好的模拟金属、玻璃等效果 |
```javascript
var sphereMaterial=new THREE.MeshLambertMaterial({
color:0xff0000,
opacity:0.7, //透明度值0~1
transparent:true //开启透明效果
});//材质对象
```
材质对象的一些属性可以在构造函数参数中设置,也可以访问材质对象的属性设置。
```javascript
material.opacity = 0.5 ;
material.transparent = true ;
```
添加高光效果
```javascript
var sphereMaterial=new THREE.MeshPhongMaterial({
color:0x0000ff,
specular:0x4488ee,
shininess:12
});//材质对象
```
### 材质常见属性
| 材质属性 | 简介 |
| --- | --- |
| color | 材质颜色,比如蓝色0x0000ff |
| wireframe | 将几何图形渲染为线框。 默认值为false |
| opacity | 透明度设置,0表示完全透明,1表示完全不透明 |
| transparent | 是否开启透明,默认false |
## threejs光源
### 常见光源类型
| 光源 | 简介 |
| --- | --- |
| [AmbientLight](http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/lights/AmbientLight) | 环境光 |
| [PointLight](http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/lights/PointLight) | 点光源 |
| [DirectionalLight](http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/lights/DirectionalLight) | 平行光,比如太阳光 |
| [SpotLight](http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/lights/SpotLight) | 聚光源 |
环境光创建
```javascript
//环境光 环境光颜色与网格模型的颜色进行RGB进行乘法运算
var ambient = new THREE.AmbientLight(0x444444);
scene.add(ambient);
```
点光源创建
```javascript
//点光源
var point = new THREE.PointLight(0xffffff);
point.position.set(400, 200, 300); //点光源位置
// 通过add方法插入场景中,不插入的话,渲染的时候不会获取光源的信息进行光照计算
scene.add(point); //点光源添加到场景中
```
光源通过add方法插入场景中,不插入的话,渲染的时候不会获取光源的信息进行光照计算
### 立体效果
仅仅使用环境光的情况下,你会发现整个立方体没有任何棱角感,这是因为环境光只是设置整个空间的明暗效果。如果需要立方体渲染要想有立体效果,需要使用具有方向性的点光源、平行光源等。
# 顶点概念、几何体结构
## 顶点位置数据解析渲染
### 自定义几何体Mesh

```javascript
var geometry = new THREE.BufferGeometry(); // 创建一个Buffer类型几何体对象
var vertices = new Float32Array([
0, 0, 0, //顶点1坐标
50, 0, 0, //顶点2坐标
0, 100, 0, //顶点3坐标
0, 0, 10, //顶点4坐标
0, 0, 100, //顶点5坐标
50, 0, 10, //顶点6坐标
]);
// 创建属性缓冲区对象
var attribute = new THREE.BufferAttribute(vertices,3);
// 设置几何体attributes属性的属性位置
geometry.attributes.position = attribute
// 测试渲染效果start
// 三角面(网格)渲染模式
var material = new THREE.MeshBasicMaterial({
color: 0x0000ff, // 三角面颜色
side: THREE.DoubleSide //两面可见
});
var mesh = new THREE.Mesh(geometry,material);
scene.add(mesh);
// 测试渲染效果end
// 辅助坐标系 参数260表示坐标系大小,可以根据场景大小设置
var axisHelper = new THREE.AxisHelper(660);
scene.add(axisHelper);
```
### 点模型Points

替换上述代码片段——“测试渲染效果”片段, 即可
```javascript
// 点渲染模式
var material = new THREE.PointsMaterial({
color: 0xff0000,
size: 10.0 // 点对象像素尺寸
})
var points = new THREE.Points(geometry,material)
scene.add(points);
```
### 线模型Line

替换上述代码片段——“测试渲染效果”片段,且去除坐标系,即可
```javascript
// 线条渲染模式
var material=new THREE.LineBasicMaterial({
color:0xff0000 //线条颜色
});//材质对象
var line=new THREE.Line(geometry,material);//线条模型对象
scene.add(line);//线条对象添加到场景中
```
### 几何体本质
一个立方体网格模型,有6个面,每个面至少两个三角形拼成一个矩形平面,每个三角形三个顶点构成,对于球体网格模型而言,同样是通过三角形拼出来一个球面,三角形数量越多,网格模型表面越接近于球形。

## 顶点颜色数据插值计算
### 顶点位置数据和颜色数据是一一对应的

```javascript
var geometry = new THREE.BufferGeometry(); //声明一个缓冲几何体对象
//类型数组创建顶点位置position数据
var vertices = new Float32Array([
0, 0, 0, //顶点1坐标
50, 0, 0, //顶点2坐标
0, 100, 0, //顶点3坐标
0, 0, 10, //顶点4坐标
0, 0, 100, //顶点5坐标
50, 0, 10, //顶点6坐标
]);
// 创建属性缓冲区对象
var attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组,作为一个顶点的xyz坐标
// 设置几何体attributes属性的位置position属性
geometry.attributes.position = attribue;
//类型数组创建顶点颜色color数据
var colors = new Float32Array([
1, 0, 0, //顶点1颜色
0, 1, 0, //顶点2颜色
0, 0, 1, //顶点3颜色
1, 1, 0, //顶点4颜色
0, 1, 1, //顶点5颜色
1, 0, 1, //顶点6颜色
]);
// 设置几何体attributes属性的颜色color属性
geometry.attributes.color = new THREE.BufferAttribute(colors, 3); //3个为一组,表示一个顶点的颜色数据RGB
//材质对象
var material = new THREE.PointsMaterial({
// 使用顶点颜色数据渲染模型,不需要再定义color属性
// color: 0xff0000,
vertexColors: THREE.VertexColors, //以顶点颜色为准
size: 10.0 //点对象像素尺寸
});
// 点渲染模式 点模型对象Points
var points = new THREE.Points(geometry, material); //点模型对象
scene.add(points); //点对象添加到场景
```
### 以上代码块分段解析
#### 材质属性 .vertexColors
没有通过材质颜色属性color设置模型颜色,直接使用定点颜色 .vertexColors
```javascript
var material = new THREE.PointsMaterial({
// 使用顶点颜色数据渲染模型,不需要再定义color属性
// color: 0xff0000,
vertexColors: THREE.VertexColors, //以顶点颜色为准
size: 10.0 //点对象像素尺寸
});
```
#### 属性缓冲区对象BufferAttribute
作为几何体BufferGeometry的顶点位置坐标属性BufferGeometry.attributes.position、顶点颜色属性BufferGeometry.attributes.color的值
#### 颜色插值
比如一条直线的端点1设置为红色,端点2设置为蓝色,整条直线就会呈现出从点1到红色点2的蓝色颜色渐变

## 顶点法向量数据光照计算
### 不设置顶点法向量数据
没有法向量数据时,带有方向性的光源不会起作用,三角形平面整个渲染效果相对暗淡,且两个三角形边界没有棱角感

```javascript
var geometry = new THREE.BufferGeometry(); //声明一个空几何体对象
//类型数组创建顶点位置position数据
var vertices = new Float32Array([
0, 0, 0, //顶点1坐标
50, 0, 0, //顶点2坐标
0, 100, 0, //顶点3坐标
0, 0, 0, //顶点4坐标
0, 0, 100, //顶点5坐标
50, 0, 0, //顶点6坐标
]);
// 创建属性缓冲区对象
var attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组
// 设置几何体attributes属性的位置position属性
geometry.attributes.position = attribue
```
### 定义几何体顶点法向量数据
定义法向量数据后,方向性光源会参与光照计算,两个三角形表面法线不同,即使光线方向相同,明暗不同,在分分界处有棱角感

```javascript
var normals = new Float32Array([
0, 0, 1, //顶点1法向量
0, 0, 1, //顶点2法向量
0, 0, 1, //顶点3法向量
0, 1, 0, //顶点4法向量
0, 1, 0, //顶点5法向量
0, 1, 0, //顶点6法向量
]);
// 设置几何体attributes属性的位置normal属性
geometry.attributes.normal = new THREE.BufferAttribute(normals, 3); //3个为一组,表示一个顶点的法向量数据
```
### API使用总结
```javascript
// 访问几何体顶点位置数据
BufferGeometry.attributes.position
// 访问几何体顶点颜色数据
BufferGeometry.attributes.color
// 访问几何体顶点法向量数据
BufferGeometry.attributes.normal
```
几何体[BufferGeometry](http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/core/BufferGeometry)的顶点法向量数据和几何体位置、颜色等顶点数据一样使用[BufferAttribute](http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/core/BufferAttribute)表示
```javascript
// 设置几何体attributes属性的位置normal属性
geometry.attributes.normal = new THREE.BufferAttribute(normals, 3); //3个为一组,表示一个顶点的法向量数据
```
## 顶点索引复用顶点数据
对于矩形网格模型而言,两个三角形有两个顶点位置是重合的。也就是说重复的位置只需定义一次,然后通过顶点数组的索引值获取这些顶点位置数据。

### 不使用顶点索引
```javascript
var geometry = new THREE.BufferGeometry(); //声明一个空几何体对象
//类型数组创建顶点位置position数据
var vertices = new Float32Array([
0, 0, 0, //顶点1坐标
80, 0, 0, //顶点2坐标
80, 80, 0, //顶点3坐标
0, 0, 0, //顶点4坐标 和顶点1位置相同
80, 80, 0, //顶点5坐标 和顶点3位置相同
0, 80, 0, //顶点6坐标
]);
// 创建属性缓冲区对象
var attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组
// 设置几何体attributes属性的位置position属性
geometry.attributes.position = attribue
var normals = new Float32Array([
0, 0, 1, //顶点1法向量
0, 0, 1, //顶点2法向量
0, 0, 1, //顶点3法向量
0, 0, 1, //顶点4法向量
0, 0, 1, //顶点5法向量
0, 0, 1, //顶点6法向量
]);
// 设置几何体attributes属性的位置normal属性
geometry.attributes.normal = new THREE.BufferAttribute(normals, 3); //3个为一组,表示一个顶点的xyz坐标
```
### 使用顶点索引.index
重合的顶点无需重复定义
```javascript
var geometry = new THREE.BufferGeometry(); //声明一个空几何体对象
//类型数组创建顶点位置position数据
var vertices = new Float32Array([
0, 0, 0, //顶点1坐标
80, 0, 0, //顶点2坐标
80, 80, 0, //顶点3坐标
0, 80, 0, //顶点4坐标
]);
// 创建属性缓冲区对象
var attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组
// 设置几何体attributes属性的位置position属性
geometry.attributes.position = attribue
var normals = new Float32Array([
0, 0, 1, //顶点1法向量
0, 0, 1, //顶点2法向量
0, 0, 1, //顶点3法向量
0, 0, 1, //顶点4法向量
]);
// 设置几何体attributes属性的位置normal属性
geometry.attributes.normal = new THREE.BufferAttribute(normals, 3); //3个为一组,表示一个顶点的xyz坐标
// 通过顶点索引组织顶点数据,顶点索引数组indexes通过索引值指向顶点位置geometry.attributes.position、顶点法向量geometry.attributes.normal中顶面数组。
// Uint16Array类型数组创建顶点索引数据
var indexes = new Uint16Array([
// 0对应第1个顶点位置数据、第1个顶点法向量数据
// 1对应第2个顶点位置数据、第2个顶点法向量数据
// 索引值3个为一组,表示一个三角形的3个顶点
0, 1, 2,
0, 2, 3,
])
// 索引数据赋值给几何体的index属性
geometry.index = new THREE.BufferAttribute(indexes, 1); //1个为一组
```
对于顶点索引而言选择整型类型数组Uint16Array等,对于非索引的顶点数据,需要使用浮点类型数组Float32Array等
| 类型数组 | 位数 | 字节 | 类型描述 | C语言等价类型 |
| --- | --- | --- | --- | --- |
| Int8Array | 8 | 1 | 有符号8位整型 | int8_t |
| Uint8Array | 8 | 1 | 无符号8位整型 | uint8_t |
| Int16Array | 16 | 2 | 有符号16位整型 | int16_t |
| Uint16Array | 16 | 2 | 无符号16位整型 | int16_t |
| Int32Array | 32 | 4 | 有符号32位整型 | int32_t |
| Uint32Array | 32 | 4 | 无符号32位整型 | uint32_t |
| Float32Array | 32 | 4 | 单精度(32位)浮点数 | float |
| Float64Array | 64 | 8 | 双精度(64位)浮点数 | double |
### BufferGeometry总结
[http://www.yanhuangxueyuan.com/upload/threejs22BufferGeometry.svg](http://www.yanhuangxueyuan.com/upload/threejs22BufferGeometry.svg)
### 
## 设置Geometry顶点位置、顶点颜色数据
几何体Geometry和缓冲类型几何体BufferGeometry表达的含义相同,只是对象的结构不同,Threejs渲染的时候会先把Geometry转化为BufferGeometry再解析几何体顶点数据进行渲染。
### [Vector3](http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/math/Vector3)定义顶点位置坐标数据
三维向量对象Vector3,可表示一个顶点的xyz坐标,顶点的法线向量
几何体Geometry的顶点位置属性geometry.vertices和缓冲类型几何体BufferGeometry顶点位置属性BufferGeometry.attributes.position是对应的。
```javascript
var geometry = new THREE.Geometry(); //声明一个几何体对象Geometry
var p1 = new THREE.Vector3(50, 0, 0); //顶点1坐标
var p2 = new THREE.Vector3(0, 70, 0); //顶点2坐标
var p3 = new THREE.Vector3(80, 70, 0); //顶点3坐标
//顶点坐标添加到geometry对象
geometry.vertices.push(p1, p2, p3);
```
### [Color](http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/math/Color)定义顶点颜色数据
几何体Geometry的顶点颜色属性geometry.colors和缓冲类型几何体BufferGeometry顶点颜色属性BufferGeometry.attributes.color是对应的。注意设置几何体Geometry顶点颜色属性geometry.colors,对网格模型Mesh是无效的,对于[点模型Points](https://www.yuque.com/hyyang-rldui/ult7v6/ovc655/edit#VR6g9)、[线模型Line](https://www.yuque.com/hyyang-rldui/ult7v6/ovc655/edit#baLEl)是有效果
```javascript
// Color对象表示顶点颜色数据
var color1 = new THREE.Color(0x00ff00); //顶点1颜色——绿色
var color2 = new THREE.Color(0xff0000); //顶点2颜色——红色
var color3 = new THREE.Color(0x0000ff); //顶点3颜色——蓝色
//顶点颜色数据添加到geometry对象
geometry.colors.push(color1, color2, color3);
```
### 材质属性.vertexColors
注意使用顶点颜色数据定义模型颜色的时候,要把材质的属性vertexColors设置为THREE.VertexColors,这样顶点的颜色数据才能取代材质颜色属性.color起作用
```javascript
//材质对象
var material = new THREE.PointsMaterial({
// color: 0xffff00,
vertexColors: THREE.VertexColors, //以顶点颜色为准
size: 10.0 // 点对象像素尺寸
});
var points = new THREE.Points(geometry,material)
scene.add(points);
```
## Face3对象定义Geometry的三角面
注意设置三角形Face3的颜色对threejs网格模型Mesh有效,对于点模型Points、线模型Line是无效

```javascript
Face3对象定义Geometry的三角面
```
## 访问几何体对象的数据