--- 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)** 在透視投影相機中,越遠的物體會有比較小的尺寸,與人類眼睛所見相同。 ![](https://i.imgur.com/XtxUrfr.png) **正交投影相機(OrthographicCamera)** 正交投影相機中的物體不論遠近,看起來的尺寸都一樣,這樣的相機一般被用在二維場景中。 ![](https://i.imgur.com/lz1AGZu.png) ```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 — 可視最遠距離 ![](https://i.imgur.com/w8OxyEn.png) > Read more about PerspectiveCamera: https://threejs.org/docs/?q=camera#api/en/cameras/PerspectiveCamera object 物體 --- ![](https://i.imgur.com/UbW2MDm.png) **內建物件** :::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 ); ``` ![](https://i.imgur.com/AWU4GBN.png) > Read more about BoxGeometry here: https://threejs.org/docs/#api/en/geometries/BoxGeometry **引入 gLTF file** ![](https://i.imgur.com/zT0bS3b.jpg) ```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`