Three.js GO GO GO === ## To-Do var directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); directionalLight.position.y = 1; scene.add(directionalLight); - model with mouse control -OBJLoader:https://threejs.org/examples/webgl_loader_obj_mtl.html -https://blog.theerrorlog.com/threejs-note-5-loading-3d-models-and-skeleton-animation.html (看不太懂) https://www.youtube.com/watch?v=mqjwgTAGQRY&index=8&list=PL08jItIqOb2qyMOhtEUoLh100KpccQiRf - audio https://howlerjs.com/ - 音效包+程式碼:https://drive.google.com/open?id=1KQ8ZfXXDdzCEcpzOhCOauYUpBGEIkTOC ```javascript= var audioLoader = new THREE.AudioLoader(); var listener = new THREE.AudioListener(); var audio = new THREE.Audio( listener ); audioLoader.load( '2.mp3', function ( buffer ) { audio.setBuffer( buffer ); audio.setLoop( false ); audio.play(); }); - awesome-audio-visualization https://github.com/willianjusten/awesome-audio-visualization - javascript syntax - Event https://hackmd.io/MwQwbGDGkCzAtJAZgUyfGAmArGeIAGbADnhQMgEYlNIQATAI1qA=# - using javascript awesome ## Basis - Node.js 是 Ryan Dahl 基於 Google 的 V8 引擎於 2009 年釋出的一個 JavaScript 開發平台,主要聚焦於 Web 程式的開發,通常用被來寫網站。 - JavaScript 其實是一個叫做 ECMAScript 標準的實作。而我們把 ECMAScript6 簡稱為 ES6。你就想成是多了很多功能的 JavaScript 就好。 - WebGL 為 OpenGL 子集(基於 OpenGL ES 2.0),是一種在任何可相容的網頁瀏覽器中描繪3D圖形 Javascript 的 API - three.js 是一個非常強大的 webGL 函式庫,將很多功能都封裝成了一個個物件,主要透過繼承的方式來做應用,也不用再花那麼久的時間跟 GLSL 打交道了。 - 教學 WebGL: 1. WebGL 與 Three.js 初探 https://ithelp.ithome.com.tw/users/20103565/ironman/1188 2. Three.js 官方文件 https://threejs.org/docs/#manual/introduction/Creating-a-scene 3. MSDN https://msdn.microsoft.com/zh-tw/library/dn479430(v=vs.85).aspx 4. https://webglfundamentals.org/ 5. https://developer.mozilla.org/zh-TW/docs/Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL 6. 着色器语言 GLSL (opengl-shader-language)入门大全 https://github.com/wshxbqq/GLSL-Card - 教學 Three.js 1. http://www.hewebgl.com/article/articledir/1 2. threejs example https://threejs.org/examples/#misc_controls_orbit - Js 1. http://eloquentjavascript.net/ ## 環境 - Q: VS Code 如何自訂? A: 透過 .vscode 資料夾中的 json 複寫預設值。 - 快捷鍵 - ctrl + r : 歷史 - ctrl + shfit + p (or F1): 主命令框 Command Palette - VS Code 的设置分为两种作用域: **用户设置(User)**(ctrl + , ): 这些设置全局应用于您打开的任何VS Code 项目 **工作区设置(Workspace)**(in Command Palette): 这些设置存储在工作区内的 .vscode 文件夹中,并且仅在打开的工作区适用。在此范围上定义的设置将覆盖用户范围的设置。 - VS Code 套件: 1. HTML Snippets (自動補完) 2. IIS Express 快速執行HTML (需先至微軟網頁安裝 Internet Information Services (IIS) 10.0 Express ) ## WebGL 觀念 ### Preparing for WebGL - 首先建立 Canvas,再用 document.querySelector 選取元素,初始化 GL context > The WebGLRenderingContext interface provides the OpenGL ES 2.0 rendering context for the drawing surface of an HTML <canvas> element. To get an object of this interface, call getContext() on a <canvas> element, supplying "webgl" as the argument. Once you have the WebGL rendering context for a canvas, you can render within it. ```javascript var canvas = document.getElementById('myCanvas'); var gl = canvas.getContext('webgl'); ``` ### About Shader - - WebGL runs on the GPU on your computer. As such you need to provide the code that runs on that GPU. You provide that code in the form of pairs of functions. Those 2 functions are called a **vertex shader**(畫哪邊) and a **fragment shader**(畫什麼顏色) and they are each written in a very strictly typed C/C++ like language called GLSL. (GL Shader Language). Paired together they are called a program. - Nearly all of the entire WebGL API is about setting up state for these pairs of functions to run. For each thing you want to draw you setup a bunch of state then execute a pair of functions by calling **gl.drawArrays or gl.drawElements** which executes your shaders on the GPU. - There are 4 ways a shader can receive data. 1. Attributes and Buffers 2. Uniforms 3. Textures 4. Varyings ## JS Syntax - 基礎 http://blog.kdchang.cc/2016/12/21/javascript101-tutorial/ ```javascript= alert("String"); <!-- Show string in browser. --> console.log("String"); <!-- Show string in console. --> ``` ### DOM 要操作 DOM 元素前要選取要操作哪個 HTML/CSS 元素,選取後可改變網頁元素內容。 - 根據ID名稱選取 document.getElementById(elementId) - 根據元素名稱選取 document.getElementsByTagName(tagName) - 根據名稱選取 document.getElementsByName(name) - 根據 Class 名稱選取 document.getElementsByClassName(classname) 有很多元素符合,回傳的是 NodeList 物件集合,使用 item() 存取 (注意 Element’s’),迭代使用 forEach 不然就要轉陣列 document 物件有提供使用 CSS 選擇器來選取元素,效能較好 - document.querySelectorAll() 方法 document 物件的 querySelectorAll() 方法可以取得 HTML 的節點陣列或清單,為一個 NodeList 物件(若要使用 map 方法需要轉陣列,不然只能用 forEach ) - document.querySelector() 方法 只會回傳一個符合的元素,沒有就回傳 null ```javascript= //<h1 id="asas"> I do not want to change. </h1> var x = document.getElementById("asas"); function changeText(x){ x.innerHTML = "fuck I am hacked!"; } ``` - Access to object ```javascript= var day1 = { squirrel: false, events: ["work", "touched tree", "pizza", "running", "television"] }; console.log(day1.squirrel); // → false console.log(day1.wolf); // → undefined day1.wolf = false; console.log(day1.wolf); // → false ``` ```javascript= var journal = []; function addEntry(events, didITurnIntoASquirrel) { journal.push({ events: events, squirrel: didITurnIntoASquirrel }); } ``` ## Three.js ### 組成 - scene - camera - renderer - geometry - material - Create a mesh( geomery, material) - Light ### Browser - To web site window flexible ```javascript= window.addEventListener( 'resize', onWindowResize, false ); // And function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize( window.innerWidth, window.innerHeight ); } ``` ### Camera - PerspectiveCamera ### Material - Using Texture ```javascript= var texture = new THREE.TextureLoader().load('image/1.jpg'); var material = new THREE.MeshBasicMaterial({ map: texture }); ``` - 畫不同的東西用不同 Material( e.g.線用LineBasicMaterial, 一般多邊形 MeshBasicMaterial) ### Position and Rotation By default, the matrixAutoUpdate property is set true, and the matrix will be automatically recalculated. If the object is static, or you wish to manually control when recalculation occurs, better performance can be obtained by setting the property false: ```javascript= object.matrixAutoUpdate = false; ``` And after changing any properties, manually update the matrix: ```javascript= object.updateMatrix(); ``` - Generate mannnyyyy object ```javascript= for( let i = 0; i < 500; i++) { var cube2 = new THREE.Mesh(geometry, material); cube2.position.x = (Math.random() - 0.5 )*1000; cube2.position.y = (Math.random() - 0.5 )*1000; cube2.position.z = (Math.random() - 0.5 )*1000; cube2.updateMatrix(); cube2.matrixAutoUpdate = false; scene.add(cube2); } ``` - Keyboard Controls Using ascii code. ```javascript= var xSpeed = 0.0001; var ySpeed = 0.0001; document.addEventListener("keydown", onDocumentKeyDown, false); function onDocumentKeyDown(event) { var keyCode = event.which; if (keyCode == 87) { cube.position.y += ySpeed; } else if (keyCode == 83) { cube.position.y -= ySpeed; } else if (keyCode == 65) { cube.position.x -= xSpeed; } else if (keyCode == 68) { cube.position.x += xSpeed; } else if (keyCode == 32) { cube.position.set(0, 0, 0); } }; ``` ## eg ```javascript= <html> <head> <meta charset="utf-8"> <title>1114ewwewew</title> </head> <body> <script src="js/three.js"></script> <script> var scene = new THREE.Scene(); // Create a Three.js scene object. var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); // Define the perspective camera's attributes. var renderer = window.WebGLRenderingContext ? new THREE.WebGLRenderer() : new THREE.CanvasRenderer(); // Fallback to canvas renderer, if necessary. renderer.setSize(window.innerWidth, window.innerHeight); // Set the size of the WebGL viewport. document.body.appendChild(renderer.domElement); // Append the WebGL viewport to the DOM. var geometry = new THREE.BoxGeometry(20, 20, 20); // Create a 20 by 20 by 20 cube. var material = new THREE.MeshBasicMaterial({ color: 0x0000FF }); // Skin the cube with 100% blue. var cube = new THREE.Mesh(geometry, material); // Create a mesh based on the specified geometry (cube) and material (blue skin). scene.add(cube); // Add the cube at (0, 0, 0). camera.position.z = 100; // Move the camera away from the origin, down the positive z-axis. var xSpeed = 10; var ySpeed = 10; document.addEventListener("keydown", onDocumentKeyDown, false); function onDocumentKeyDown(event) { var keyCode = event.which; if (keyCode == 87) { cube.position.y += ySpeed; } else if (keyCode == 83) { cube.position.y -= ySpeed; } else if (keyCode == 65) { cube.position.x -= xSpeed; } else if (keyCode == 68) { cube.position.x += xSpeed; } else if (keyCode == 32) { cube.position.set(0, 0, 0); } }; var render = function () { renderer.render(scene, camera); // Each time we change the position of the cube object, we must re-render it. requestAnimationFrame(render); // Call the render() function up to 60 times per second (i.e., up to 60 animation frames per second). }; render(); // Start the rendering of the animation frames. </script> </body> </html> ``` ### 文件解讀 (? - Catmull Rom spline : 差值法,輸入點輸出一條經過所有點的曲線。 - 設定 Material 為重複材質 將 texture.wrapS and texture.wrapT 設為THREE.RepeatWrapping ```javascript= var texture = new THREE.TextureLoader().load('image/1.jpg'); var geometry = new THREE.BoxGeometry(20, 20, 20); var material = new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true, map: texture }); texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping; texture.repeat.set(4, 4);//表面上的重複程度 ``` - Move Texture map 就是存取 material 中的 texture 內容,offset 則是texture 裡的載入座標 ```javascript= material.map.offset.x += 0.01; ``` ### add audio ```javascript= <audio src="music.mp3" autoplay loop></audio>///背景無限撥放 ```