WebGL:3D 圖形在瀏覽器中的入門指南
你好,未來的 3D 圖形魔法師!我很興奮能成為你進入 WebGL 世界的引路人。作為一個教學計算機圖形多年的老師,我可以告訴你,WebGL 就像是一根魔杖,為你的瀏覽器帶來魔法。它讓你能在網頁中創建令人驚艷的 3D 圖形和動畫。這不是很酷嗎?我們一起來探索吧!
什麼是 WebGL?
WebGL,全名為 Web 圖形庫,是一個 JavaScript API,讓你能在任何兼容的瀏覽器中無需插件即可渲染互動的 2D 和 3D 圖形。這就像是給你的瀏覽器賦予超能力,創造出令人驚奇的視覺體驗!
簡短歷史
WebGL 首次在 2011 年推出,從那時起,它改變了我們對網頁上圖形的看法。在 WebGL 出現之前,如果你想在瀏覽器中創建 3D 圖形,你需要依賴於如 Flash 或 Java 小程序之類的插件。現在,有了 WebGL,我們可以直接在瀏覽器中原生地做這些事情。這就像我們從自行車升級到了跑車!
預備知識
在我們開始 WebGL 冒險之前,讓我們確保我們背包裡有正確的工具:
- 一個現代的瀏覽器(Chrome、Firefox、Safari 或 Edge)
- 一個文本編輯器(我推薦 Visual Studio Code,但任何編輯器都可以)
- HTML 和 JavaScript 的基本知識(如果你忘記了,別擔心,我們會邊學邊進行)
開始使用 WebGL
讓我們創建我們的第一個 WebGL 程式!我們將從一個簡單的 "Hello, WebGL!" 示例開始,它在螢幕上顯示一個有顏色的三角形。
步驟 1:設置 HTML
首先,我們需要創建一個 HTML 檔案,並在其中包含一個 canvas 元素。這個 canvas 將是我們 WebGL 魔法發生的地方。
<!DOCTYPE html>
<html lang="zh-tw">
<head>
<meta charset="UTF-8">
<title>Hello, WebGL!</title>
<style>
canvas { border: 1px solid black; }
</style>
</head>
<body>
<canvas id="glCanvas" width="640" height="480"></canvas>
<script src="webgl-demo.js"></script>
</body>
</html>
在這個 HTML 中,我們創建了一個 ID 為 "glCanvas" 的 canvas 元素,並將其尺寸設為 640x480 像素。我們還鏈接了一個名為 "webgl-demo.js" 的 JavaScript 檔案,我們將在其中寫入 WebGL 代碼。
步驟 2:初始化 WebGL
現在,讓我們創建 "webgl-demo.js" 檔案並開始寫入一些 JavaScript 代碼以初始化 WebGL:
function main() {
const canvas = document.getElementById("glCanvas");
const gl = canvas.getContext("webgl");
if (!gl) {
alert("無法初始化 WebGL。您的瀏覽器或電腦可能不支持它。");
return;
}
// 設置清空顏色為黑色,完全不透明
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// 使用指定的清空顏色清空顏色緩存
gl.clear(gl.COLOR_BUFFER_BIT);
}
window.onload = main;
讓我們分解這段代碼:
- 我們獲取 canvas 元素的引用。
- 我們嘗試從 canvas 獲取 WebGL 緩存。如果失敗,表示 WebGL 不被支持,我們顯示一個錯誤訊息。
- 如果成功,我們設置背景色為黑色並清空畫布。
步驟 3:創建 Shaders
Shaders 是運行在 GPU 上的特殊程序。它們使用一種叫做 GLSL(OpenGL 著色語言)的語言編寫。我們需要兩種類型的 shaders:頂點著色器和片段著色器。
// 頂點著色器程序
const vsSource = `
attribute vec4 aVertexPosition;
void main() {
gl_Position = aVertexPosition;
}
`;
// 片段著色器程序
const fsSource = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
頂點著色器負責定位我們的頂點,而片段著色器則負責給我們的像素上色(在這個例子中是紅色)。
步驟 4:初始化著色器程序
現在,我們需要編譯並鏈接這些著色器到一個著色器程序中:
function initShaderProgram(gl, vsSource, fsSource) {
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('無法初始化著色器程序:' + gl.getProgramInfoLog(shaderProgram));
return null;
}
return shaderProgram;
}
function loadShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert('編譯著色器時發生錯誤:' + gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
這段代碼編譯我們的著色器,將它們鏈接到一個程序中,並檢查是否有任何錯誤。
步驟 5:創建三角形
現在,讓我們創建三角形的數據:
function initBuffers(gl) {
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
const positions = [
-1.0, 1.0,
1.0, 1.0,
-1.0, -1.0,
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
return {
position: positionBuffer,
};
}
這創建了一個緩存並用三角形的頂點位置填充它。
步驟 6:繪製場景
最後,讓我們把所有東西放在一起並繪製我們的三角形:
function drawScene(gl, programInfo, buffers) {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(programInfo.program);
gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
gl.vertexAttribPointer(
programInfo.attribLocations.vertexPosition,
2, // 每次迭代 2 個分量
gl.FLOAT, // 數據是 32 位浮點數
false, // 不標準化
0, // 跨度(0 = 自動)
0 // 缓存中的偏移量
);
gl.drawArrays(gl.TRIANGLES, 0, 3);
}
這個函數清空畫布,設置著色器程序,連接緩存數據,並最終繪製三角形。
把所有東西放在一起
現在,讓我們更新我們的 main
函數來使用所有這些部分:
function main() {
const canvas = document.getElementById("glCanvas");
const gl = canvas.getContext("webgl");
if (!gl) {
alert("無法初始化 WebGL。您的瀏覽器或電腦可能不支持它。");
return;
}
const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
const programInfo = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
},
};
const buffers = initBuffers(gl);
drawScene(gl, programInfo, buffers);
}
window.onload = main;
這就是你的第一個 WebGL 程式。當你在瀏覽器中打開 HTML 檔案時,你應該會在黑色背景上看到一個紅色三角形。恭喜你!
常見 WebGL 方法
這裡是我們使用過的一些常見 WebGL 方法和它們的用途:
方法 | 用途 |
---|---|
gl.createBuffer() |
創建一個新的緩存對象 |
gl.bindBuffer() |
將緩存對象綁定到一個目標 |
gl.bufferData() |
初始化並創建緩存對象的數據存儲 |
gl.createShader() |
創建一個著色器對象 |
gl.shaderSource() |
設置著色器對象的源代碼 |
gl.compileShader() |
編譯著色器對象 |
gl.createProgram() |
創建一個程序對象 |
gl.attachShader() |
將著色器對象附加到程序對象 |
gl.linkProgram() |
鏈接程序對象 |
gl.useProgram() |
將指定的程序設置為當前的渲染狀態的一部分 |
gl.getAttribLocation() |
返回屬性變量的位置 |
gl.enableVertexAttribArray() |
啟用頂點屬性數組 |
gl.vertexAttribPointer() |
指定頂點屬性數據的佈局 |
gl.drawArrays() |
從數組數據渲染原始形状 |
結論
哇,我們今天學習了許多內容!我們學習了 WebGL 是什麼,設置了我們的開發環境,並創建了我們的第一個 WebGL 程式。記住,學習 WebGL就像學習騎自行車一樣 - 起初可能會有些晃動,但隨著練習,你會很快馳騁!
在未來的課程中,我們將探索更複雜的形狀,添加互動性,甚至深入 3D 圖形。WebGL 的世界浩瀚而令人興奮,我迫不及待地想和你一起探索更多。下次見,快樂編程!
Credits: Image by storyset