大家好,大家都叫我西瓜。因為想轉職寫遊戲,而遊戲中會讓人第一個想到、也是能在第一瞬間吸引人的就是畫面了,筆者從事網站開發多年,也就順勢從 WebGL 開始學習,這系列文章將以做出範例的方式,跟大家分享這幾個月學習的心得
這系列文章假設讀者能夠看懂 Javascript,並且對於 Web 技術有基礎的了解
簡單來說,WebGL 是一組在 Web 上操作 GPU 的 Javascript API,而 WebGL 絕大部分的 API 都可以找到 openGL 上對應的版本,且名字幾乎沒有差別,猜測制定 WebGL 標準時只打算做一層薄薄的包裝,這樣一方面瀏覽器可能比較好實做,但是也因此 WebGL 直接使用時是非常底層的,甚至偶爾會需要去算線性代數、矩陣的東西
看到這邊讀者們可能會想說:哇,我要來把 Tab 關掉了,洗洗睡。老實說,如果對於基礎原理沒有興趣,想要『快速』做出東西,這邊確實可以左轉 three.js 或是 babylon.js,筆者是基於下面這個因素決定學習 WebGL 的:
當你了解其原理時,比較不容易受到框架、潮流演進的影響
為什麼?在了解原理的狀況下,比較能知道框架幫你做了什麼,遇到變化比較大的需求的時候可能比較容易想到方法應對;前端技術更迭速度大家都知道,但是基礎原理是不會有太大的變化的;最後,透過 WebGL 學到的原理多多少少也能應用在其他平台上吧
筆者近期學習 WebGL 所使用的資源主要是 WebGL2 Fundamentals,這個網站上的教學寫的非常完整,從基礎一路到各個功能的實做,因此本次鐵人賽系列文章所提及的概念或多或少會與這個網站重疊,有興趣的讀者不妨交互參考看看;同時,如果有大大發現文章內容有誤,歡迎使用我的網站這邊的聯絡方式聯絡我改正,感謝!
要製作範例,我們會需要編輯器,任何純文字編輯器皆可,接著透過瀏覽器執行網頁,理論上最新版 Chrome, Firefox, Edge 以及 Safari 都可以,WebGL 在這些瀏覽器都可以使用,筆者將使用 Chrome 示範;除此之外,我們需要一種方法讓瀏覽器讀取我們寫的網頁,這邊可以使用任何靜態網頁伺服器,例如:
http-server
會開啟網頁伺服器,以當前的工作目錄當成網站根目錄,預設把 port 開在 8080
,可以透過 http://localhost:8080
打開網站,同時具有檢視資料夾的功能ruby -run -ehttpd . -p8000
: ruby 內建的網頁伺服器,與 http-server
類似,執行後 commandline 當前的工作目錄當成網站根目錄,-p8000
意思是 port 開在 8000
,可以透過 http://localhost:8000
打開網站python3 -m http.server
/ python -m SimpleHTTPServer
: python 內建的網頁伺服器,預設把 port 開在 8000
,可以透過 http://localhost:8000
打開網站準備好開發用網頁伺服器,就可以來建立第一個範例的 HTML 檔案: 01-hello-webgl.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01-hello-webgl</title>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="module" src="01-hello-webgl.js"></script>
</body>
</html>
這邊可以看到有一個 <canvas id="canvas"></canvas>
,這就是 WebGL 操作的『畫布』,WebGL 繪製的東西將透過這個元素呈現,另外 <script type="module" src="01-hello-webgl.js"></script>
以 ES Module 的形式引入我們主要要寫的 Javascript: 01-hello-webgl.js
console.log('hello')
先這樣就好,使用瀏覽器透過網站伺服器打開 01-hello-webgl.html
,並且按下 F12 或是右鍵檢視元件開啟開發者工具,接著應該可以在 Console 看到 hello
表示一切正常:
為了確保之後對原始碼的更動在瀏覽器重整時使用更動後的版本,建議切換至 Network tab 關閉快取,以 Chrome 為例:
要取得 WebGL instance,我們透過 <canvas />
JS DOM API 的 .getContext()
並且傳入 'webgl'
來取得,像是這樣:
const canvas = document.getElementById('canvas');
const gl = canvas.getContext('webgl');
window.gl = gl;
第一行透過 id 取得元素,取得 gl
之後也設定到 window.gl
上方便在開發工具 Console 中玩轉:
另一個常見的繪製 API 為 CanvasRenderingContext2D,這時要傳入的字串就變成
'2d'
:.getContext('2d')
,在之後繪製文字的時候會需要這邊的幫忙
老實說,我們距離繪製一些有意義的東西還有點遙遠,不過倒是可以先找個顏色填滿(事實上是清除)畫面讓第一天有點東西
首先要透過 gl.clearColor(red, green, blue, alpha)
設定清除用的顏色,這邊 red, green, blue, alpha 是介於 0 - 1 之間的浮點數,設定好之後,gl.clear(gl.COLOR_BUFFER_BIT)
進行清除,而 gl.COLOR_BUFFER_BIT
是用來指定清除顏色的部份,以筆者的主題色 #6bde99
/ rgb(108 225 153)
為例,大概像是這樣:
gl.clearColor(108/255, 225/255, 153/255, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
雖然只是拿油漆工具填滿整張畫布,但是第一天至少讓畫面有點東西了,畫面上的綠色區塊就是 <canvas>
,因為我們沒有設定長寬,在 Chrome 上預設的大小是 300x150
光是從 gl.clearColor
/ gl.clear
這兩個就可以感受到 WebGL 是來自另外一個世界的 API,在 GPU 這邊許多東西都是介於 0 到 1 之間的浮點數,而 gl.COLOR_BUFFER_BIT
更是體現跟底層溝通用的 bit flag
本篇的完整程式碼可以在這邊找到:
明天開始來繪製 GL 最常見的基本元素:三角形,並介紹繪製的基本流程