# threejs练习
**Repository Path**: dttx123/threejs_exercise
## Basic Information
- **Project Name**: threejs练习
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2019-10-16
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# THREEJS 入门基础知识
## three.js是什么
WebGL(Web Graphics Library)是一种3D绘图协议,它允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型。
使用WebGL原生的API来写3D程序非常复杂,需要相对较多的数学知识,对于前端开发者来说学习成本较高。而Three.js对WebGL提供的接口进行了非常好的封装,简化了很多细节,大大降低了学习成本,成为前端开发者完成3D绘图的得力工具,目前在github上star数量已经达到了将近4万+。
## 三大基本组件
three.js使用面向对象的方式来构建程序,包含3个基本对象: 场景(scene), 相机(camera), 以及一个渲染器(renderer)。 比如看春晚,场景对应于整个舞台,相机是拍摄镜头,渲染器用来把拍摄好的舞台画面显示在电视屏幕上, 有了这三样东西, 才能够使用相机将场景渲染到网页上去。

### 场景
场景是所有物体的容器,如果要显示一个苹果,就需要将苹果对象加入场景中。在Threejs中场景就只有一种,用THREE.Scene来表示,要构件一个场景也很简单,只要new一个对象就可以了,代码如下:
```js
var scene = new THREE.Scene(); //创建场景
```
### 相机
相机就像人的眼睛一样,人站在不同位置,抬头或者低头都能够看到不同的景色。
场景只有一种,但是相机却又很多种, 不同的相机呈相的结果不同, 可以用不同的场景, (比如人像,风景,微距), 对开发者来说,只要设置不同的相机参数,即可;
```js
// 创建透视相机
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
scene.add(camera); //添加相机
```
### 渲染器
渲染器的作用就是将相机拍摄出的画面在浏览器中呈现出来。渲染器决定了渲染的结果应该画在页面的什么元素上面,并且以怎样的方式来绘制。three.js中有很多种类的渲染器,例如webGLRenderer、canvasRenderer、SVGRenderer,通常使用的是webGL渲染器。
```js
var renderer = new THERR.WebGLRenderer(); // 创建webGL渲染器
renderer.render(scene,camera); // 渲染
```
创建好染器后,需要调用render方法将之前创建好的场景和相机相结合从而渲染出来,即调用渲染器的render方法。
### 第一个场景
下面的代码, 我们将建立一个场景和一个旋转的立方体:
```js
My first Three.js app
```
## 轨道控制器
轨道控制器OrbitControls.js是一个神奇的控件,可以实现场和鼠标、键盘交互,让场景动起来,控制场景的旋转、平移,缩放; 轨道控制器本质上改变的并不是场景,而是相机的参数,相机的位置角度不同,同一个场景的渲染效果是不一样,比如一个相机绕着一个场景旋转,就像场景旋转一样。 OrbitControls是对Three.js正投影相机和透视投影相机对象进行封装的,你想深入了解相机控制器OrbitControls的每一个功能,可以阅读Three.js\examples\js\controls目录下的OrbitControls.js 文件
**构造函数参数数说明**
```js
new THREE.OrbitControls(object: Camera,domElement: HTMLDOMElement)
// object: 控制的相机
// domElement: 可选的,指定在特定的元素(例如画布 renderer.domElement)上工作
```
**属性:**
|属性名|说明|
|--|--|
|autoRotate| Boolean 默认false。设定为true时,相机自动围绕目标旋转但必须在animation中循环调用update();|
|autoRotateSpeed| Float 当前者为true时默认2.0,代表每轮60fps用时30s,值越小转动越慢|
|rotateSpeed| Float 旋转速度(ORBIT的旋转速度,鼠标左键),默认1|
|domElement| HTMLDOMElement 侦听鼠标/触摸事件,必须在构造函数中传递,用作特性值更改后不会重新设置事件侦听器 默认是整个文档|
|enableDamping| Boolean 默认false。设置为true则启用阻尼(惯性),用来给控制相机一个重量,必须调用update()在你的animation循环中|
|dampingFactor| Float 前者为true时使用阻尼惯性(可理解为阻止向一个方向移动)|
|enabled| Boolean 是否启用控件,默认true|
|enableKeys| Boolean 能否用键盘控制,默认true ←↑→↓四个键控制物体的移动|
|keys| Object 控制相机平移的四个键。默认四个箭头键{LEFT: 37,UP: 38,RIGHT: 39,DOWM:40} 所有的键值|
|enablePan| Boolean 相机平移,默认true|
|panSpeed| Float 移动的速度,默认1|
|keyPanSpeed| Float 相机平移的速度,默认每按一次控制方向键移动7.0像素|
|enableRotate| Boolean 水平垂直旋转相机,默认true。只想控制单轴,通过PolarAngle/AzimuthAngle的最小值和最大值设置为相同的值,这将导致垂直|
|maxAzimuthAngle| Float 水平旋转,范围Math.PI~Math.PI 或者Infinity 默认Infinity|
|minAzimuthAngle| Float 水平旋转,范围Math.PI~Math.PI 或者Infinity 默认Infinity|
|maxPolarAngle| Float 垂直旋转,范围0~Math.PI 默认Math.PI|
|minPolarAngle| Float 垂直旋转,范围0~Math.PI 默认0|
|maxDistance| Float 拉远镜头(只能用在PerspectiveCamera),默认Infinity|
|minDistance| Float 拉近镜头,默认0|
|maxZoom| Float 拉远镜头(只能用在OthorgraphicCamera),默认Infinity|
|minZoom| Float拉近镜头,默认0|
|mouseButton| Object {ORBIT: THREE.MOUSE.LEFT,ZOOM: THREE.MOUSE.MIDDLE,PAN: THREE.MOUSE.RIGHT} 鼠标控制缩放移动和旋转|
|object| Camera 正在控制的相机|
|position0| Vector3 在reset()和saveState()内部使用|
|screenSpacePaning| Boolean 平移时摄像机位置的转换。true,相机的平移在屏幕空间;false,摄像机在与摄像机向上方向正交的平面上平移,默认false|
|target| Vector3在reset()和saveState()内部使用|
|zoom0| Vector3 在reset()和saveState()内部使用|
|zoomSpeed| Float zoom(变焦)的速度,默认1|
**方法:**
| 方法名 | 说明 |
| ------------------- | ------------------------------------------------------------ |
| dispose() | null 移除所有的事件监听 |
| getAzimuthalAngle() | radians 获得用弧度表示的当前水平旋转角度 |
| getPolarAngle() | radians获得用弧度表示的当前垂直旋转角度 |
| reset() | null 通过最近一次调用saveState()或者初始状态来重置为当前的状态 |
| saveState() | null 保存当前控制的状态,可以稍后通过reset()来恢复 |
| update() | false 更新控件,在手动改变了摄像机的钻换后必须调用。在设置了autoRotate或enableDamping时也要在循环中调用 |
**事件**
|事件名称|说明|
|-|-|
|change|OrbitControls的变化事件|
对于一个静态的场景,可能不需要一直周期性调用渲染函数渲染场景,而是鼠标旋转缩放场景的时候才重新渲染,就可以通过OrbitControls的变化事件change监听触发函数调用渲染函数render。
```js
// 渲染函数
function render() {
renderer.render(scene, camera);
}
varcontrols = newTHREE.OrbitControls(camera);
//监听鼠标事件,触发渲染函数,更新canvas画布渲染效果
controls.addEventListener('change', render);
```
## dat.GUI.js 界面组件
dat.GUI 是一个轻量级的图形用户界面库,使用这个库可以很容易地创建出能够改变代码变量的界面组件

### 使用步骤
1 引包
```js
```
2 定义一个 JavaScript 对象(如:controls),该对象中保存要通过 dat.GUI 改变的属性
```js
var controls = new function () {
this.rotationSpeed = 0.02;
//......
};
```
3 接下来需要将这个 JavaScript 对象传递给 dat.gui 对象,并设置各个属性的取值范围
```js
var gui = new dat.GUI();
gui.add(controls, 'rotationSpeed', 0, 0.5);
```
4 最后当用户对 dat.GUI 控件进行操作时,controls 里的属性值也会同步修改。在程序中直接引用这个属性值即可
### 控件类型
> dat.GUI 会根据我们设置的属性类型来渲染使用不同的控件。
#### 数字类型(Number)
```js
// contorls 存放需要改变的属性
var controls = new function () {
this.rotationSpeed = 0.02;
};
```
+ 如果没有设置限制条件,则为一个 input 输入框。
```js
var gui = new dat.GUI();
gui.add(controls, 'rotationSpeed').name('旋转速度'); // name方法指定别名
```
+ 可以设置最小值最大值范围,则显示为 slider 滑块组件(当然右侧还是有 input 输入)
```js
var gui = new dat.GUI();
gui.add(controls, 'rotationSpeed', 0, 0.5);
```
+ 还可以只单独限制最小值或者最大值,这个同样为一个 input 输入框。
```js
var gui = new dat.GUI();
gui.add(controls, 'rotationSpeedX').min(0);
gui.add(controls, 'rotationSpeedY').max(10);
```
+ 可以配合 step 限制步长。
```js
var gui = new dat.GUI();
gui.add(controls, 'rotationSpeedX').step(0.5);
gui.add(controls, 'rotationSpeedY', 0, 3).step(0.5);
gui.add(controls, 'rotationSpeedZ').max(10).step(0.5);
```
+ 如果数字只是有限的几种固定值,那还可以使用下拉框的形式。
```js
var gui = new dat.GUI();
gui.add(controls, 'rotationSpeed', { Stopped: 0, Slow: 0.02, Fast: 5 });
```
#### 字符串类型(String)
+ 默认情况下就是一个 input 输入框。
```js
var controls = new function () {
this.site = "hangge.com"
};
var gui = new dat.GUI();
gui.add(controls, 'site');
```
+ 只是有限的几种固定值,那还可以使用下拉框的形式。
```js
var controls = new function () {
this.site = "hangge.com"
};
var gui = new dat.GUI();
gui.add(controls, 'site', [ 'google.com', 'hangge.com', '163.com' ]);
```
#### 布尔类型(Boolean )
+ 使用复选框(Checkbox)的形式控制
```js
var controls = new function () {
this.visible = true
};
var gui = new dat.GUI();
gui.add(controls, 'visible');
```
#### 自定义函数(Function)
使用按钮(button)的形式控制,点击按钮会调用相应的方法。
```js
var controls = new function () {
this.hello = function() {
alert("欢迎访问 hangge.com");
}
};
var gui = new dat.GUI();
gui.add(controls, 'hello');
```
#### 颜色值
dat.GUI 一共提供了 4 种类型颜色输入控制:CSS、RGB、RGBA、Hue(注意:颜色使用 addColor 方法添加控件)
```js
var controls = new function () {
this.color0 = "#ffae23"; // CSS string
this.color1 = [0, 128, 255]; // RGB array
this.color2 = [0, 128, 255, 0.3]; // RGB with alpha
this.color3 = {h: 350, s: 0.9, v: 0.3}; // Hue, saturation, value
};
var gui = new dat.GUI();
gui.addColor(controls, 'color0');
gui.addColor(controls, 'color1');
gui.addColor(controls, 'color2');
gui.addColor(controls, 'color3');
```
### 事件监听
对于面板中的每一个控制项,我们都可以设置 onChange 和 onFinishChange 监听事件。
```js
var controls = new function () {
this.speed = 1;
};
var gui = new dat.GUI();
var speedController = gui.add(controls, 'speed', 0, 5);
//对应控制项值改变时响应(比如拖动滑块过程中)
speedController.onChange(function(value) {
//value 要改变的数据
console.log("onChange:" + value)
});
//对应控制项值修改完毕响应
speedController.onFinishChange(function(value) {
console.log("onFinishChange" + value)
});
```
### 选项组
可以使用文件夹给选项分组
```js
var gui = new dat.GUI();
// 第一组
var f1 = gui.addFolder('Flow Field');
f1.add(text, 'speed');
f1.add(text, 'noiseStrength');
// 第二组
var f2 = gui.addFolder('Letters');
f2.add(text, 'growthSpeed');
f2.add(text, 'maxSize');
f2.add(text, 'message');
// 展开第二组
f2.open();
```
## 把模型渲染到场景
下面代码是将一个立方体添加到场景中:
```js
// 1-创建立方体几何模型
var geometry = new THREE.BoxGeometry(1, 1, 1);
// 2-创建基础材质对象
var material = new THREE.MeshBasicMaterial({
color: 0x00ff00
});
// 3-创建网格模型
var cube = new THREE.Mesh(geometry, material);
// 4-将网格模型添加到 场景中
scene.add(cube);
```