---
title: 'Three.js 學習筆記'
tags: 教育訓練
disqus: hackmd
---
Three.js 學習筆記
===
## Table of Contents
[TOC]
## 大綱
* 場景(Scene):供其他元素設置的空間。
* 相機(Camera):在場景中建立觀察點,並確定觀察方向、角度。
* 物體(Objects):在場景中添加被觀察的物體。
* 光源(Light):在場景中用來照亮物體的光。
* 渲染器(Renderer):將所要呈現的場景渲染到畫面上。
## Scene 場景
> 所有東西都從裡開始 用.add() 將物件加進去
>
```javascript=
scene.add(obj)
```
Camera 視角
---
> 可以想像成我們的視角,可以控制位置,面向
```javascript=
camera.position.set(x,y,z) // 設定位置
```
```javascript=
camera.lookAt(x,y,z) // 設定面向
```
> 不同種類的 camera 可以做不同的事
>
**透視投影相機(PerspectiveCamera)**
在透視投影相機中,越遠的物體會有比較小的尺寸,與人類眼睛所見相同。

**正交投影相機(OrthographicCamera)**
正交投影相機中的物體不論遠近,看起來的尺寸都一樣,這樣的相機一般被用在二維場景中。

```js=
const camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
```
**Constructor**
```javascript=
PerspectiveCamera (
fov : Number,
aspect : Number,
near : Number,
far : Number
)
```
fov — 視角寬度
aspect — 畫面比例
near — 可視最近距離
far — 可視最遠距離

> Read more about PerspectiveCamera: https://threejs.org/docs/?q=camera#api/en/cameras/PerspectiveCamera
object 物體
---

**內建物件**
:::info
Three.js 中內建許多,幾何形可以使用,搭配材質(material),即可創建物體。
:::
```javascript=
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
```

> Read more about BoxGeometry here: https://threejs.org/docs/#api/en/geometries/BoxGeometry
**引入 gLTF file**

```javascript=
// Instantiate a loader
const loader = new GLTFLoader();
var model2 = new THREE.Object3D(); // 用來存放模型
// Load a glTF resource
loader.load(
// resource URL
'models/gltf/duck/duck.gltf',
// called when the resource is loaded
function ( gltf ) {
model2 = gltf.scene; //載入完成後 存在全域變數中
model2.traverse(function (node) {
if (node.isMesh) {
// node.material.needsUpdate = true;
// node.material.envMapIntensity = 1;
// node.material.envMap = textureEquirec;
// node.material.metalness = 0.5;
// node.material.roughness = 0.4;
}
});
model2.scale.set(0.05, 0.05, 0.05); // 縮放大小
scene.add(model2); // 加入場景
},
// called while loading is progressing
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
// called when loading has errors
function ( error ) {
console.log( 'An error happened' );
}
);
```
:::success
這邊有個 traverse 方法,這是 THREE.Scene 中提供一個用來遍歷目標物件及其所有後代的方法,透過傳入的 function,可以對目標底下的所有子元件都設定效果。
:::
Light 燈光
---
**環境光 AmbientLight**
> 環境光。散佈在環境中的光,會將光源的顏色疊加到場景中所有物體上,不能創造陰影,通常拿來增加一些柔性的光線補強色彩。
>
**點光源 PointLight**
> 點光源。從特定一點向所有方向發射光線,可以投射陰影。類似燈泡、螢火蟲的概念。
>
**聚光燈 SpotLight**
> 聚光燈。從特定一點對某個方向發射錐形的光線,可以投射陰影。類似手電筒、舞台聚光燈的概念。
>
**方向光 DirectionLight**
> 平行光、無限光。從一個二維平面發射光線,光線彼此平行,可以投射陰影,類似太陽光的概念。
[前四項燈光範例](https://dezchuang.github.io/ironman-three.js/day09_light/index.html)
**半球光 HemisphereLight**
> 用來模擬真實世界的環境光,一部份是從上方照射模擬太陽光,一部分是從下方反射地面後照射到物體
[半球光範例](https://threejs.org/examples/?q=Hemisphere#webgl_lights_hemisphere)
**專案中實際應用**
```javascript=
let spotLight = new THREE.SpotLight(0xeeff00) // 燈光顏色
spotLight.position.set(-10, 20, 20) // 擺放位置
spotLight.castShadow = true // 照射到物體 是否產生陰影
scene.add(spotLight)
let spotLightHelper = new THREE.SpotLightHelper(spotLight) // 加上輔助線 方便做調整
scene.add(spotLightHelper)
```
Renderer 渲染器
---
```javascript=
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
if (resizeRendererToDisplaySize(renderer)) {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
};
animate();
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
var width = window.innerWidth;
var height = window.innerHeight;
var canvasPixelWidth = canvas.width / window.devicePixelRatio;
var canvasPixelHeight = canvas.height / window.devicePixelRatio;
const needResize =
canvasPixelWidth !== width || canvasPixelHeight !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
```
:::success
**requestAnimationFrame** has a number of advantages. Perhaps the most important one is that it pauses when the user navigates to another browser tab, hence not wasting their precious processing power and battery life.
:::
## CatmullRomCurve3 曲線
概念: 先用關鍵點,用演算法算出路徑,再用此路徑繪製ExtrudeGeometry,也就是沿著路徑用多邊形連接起來的水管狀幾何形。
```javascript=
// 劃出目標點
const curve = new THREE.CatmullRomCurve3(
[...vectorArray],
props.isClosed,
"catmullrom",
0.5
);
// 繪製軌道
// Set up settings for later extrusion
var extrudeSettings = {
steps: 200,
// 幾個切面
bevelEnabled: false,
extrudePath: curve, //套用我們算好的路徑
};
// // Define a triangle
var pts = [],
// 橫切面 是幾邊型
count = 5; //五邊形
for (var i = 0; i < count; i++) {
var l = 0.5;
// 邊長
var a = ((2 * i) / count) * Math.PI;
pts.push(new THREE.Vector2(Math.cos(a) * l, Math.sin(a) * l));
}
var shape = new THREE.Shape(pts);
// Extrude the triangle along the CatmullRom curve
var geometryLine = new THREE.ExtrudeGeometry(shape, extrudeSettings);
var materialLine = new THREE.MeshLambertMaterial({
color: 0x262626,
wireframe: false,
});
// Create mesh with the resulting geometry
var mesh = new THREE.Mesh(geometryLine, materialLine);
scene.add(mesh);
```
## Appendix and FAQ
:::info
**Find this document incomplete?** Leave a comment!
:::
###### tags: `Templates` `Documentation`