WebGL - 繪製模型:初學者指南

您好,未來的 WebGL 巫師們!我很興奮能成為您踏進 3D 圖形編程世界的引路人。作為一個教了多年計算機科學的人,我可以告訴你,在 WebGL 中繪製模型就像用數字樂高積木建造一樣——這個挑戰充滿了樂趣!讓我們一起深入探索,在螢幕上創造魔法。

WebGL - Drawing a Model

理解基礎知識

在我們開始繪製模型之前,讓我們快速回顧一下 WebGL 是什麼。WebGL(Web 圖形庫)是一個 JavaScript API,讓我們能在網頁瀏覽器中無需任何插件就能渲染 3D 圖形。這就像是給你的網頁頁面賦予超能力!

現在,當我們在 WebGL 中繪製模型時,我們主要有兩種方法可以使用:

繪製方法

方法 描述 使用情境
drawArrays() 使用數組數據繪製基本圖形 簡單形狀,非索引幾何
drawElements() 繪製索引基本圖形 複雜模型,優化渲染

讓我們詳細探討這兩種方法。

drawArrays() 方法:簡化繪製

drawArrays() 是什麼?

drawArrays() 方法就像是用鉛筆素描——直接且適合簡單形狀。這個方法使用頂點數據數組來繪製幾何基本圖形。

語法與參數

gl.drawArrays(mode, first, count);
  • mode:要繪製的基本圖形類型(例如,gl.TRIANGLES,gl.LINES)
  • first:數組中的起始索引
  • count:要繪製的頂點數量

範例:繪製三角形

讓我們使用 drawArrays() 繪製一個簡單的三角形:

// 三角形的頂點數據
const vertices = [
0.0,  0.5,  0.0,  // 頂部頂點
-0.5, -0.5,  0.0,  // 底部左側頂點
0.5, -0.5,  0.0   // 底部右側頂點
];

// 創建並綁定緩衝區
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

// 設置屬性指針
const positionAttributeLocation = gl.getAttribLocation(program, 'a_position');
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 3, gl.FLOAT, false, 0, 0);

// 繪製三角形
gl.drawArrays(gl.TRIANGLES, 0, 3);

在這個範例中,我們定義了三個頂點來構成我們的三角形,創建一個緩衝區來存儲這些數據,設置屬性指針來告訴 WebGL 如何讀取我們的頂點數據,最後調用 drawArrays() 來渲染我們的三角形。

drawElements() 方法:創建複雜模型

drawElements() 是什麼?

如果 drawArrays() 是用鉛筆素描,那麼 drawElements() 就是用水彩筆繪畫——它給你在繪製複雜形狀時提供更多的控制性和效率。這個方法使用索引渲染,讓我們可以重用頂點數據。

語法與參數

gl.drawElements(mode, count, type, offset);
  • mode:要繪製的基本圖形類型
  • count:要繪製的元素數量
  • type:元素數組緩衝區中的值類型
  • offset:元素數組緩衝區中的偏移量

範例:繪製正方形

讓我們使用 drawElements() 繪製一個正方形:

// 正方形的頂點數據
const vertices = [
-0.5,  0.5,  0.0,  // 頂部左側
0.5,  0.5,  0.0,  // 頂部右側
0.5, -0.5,  0.0,  // 底部右側
-0.5, -0.5,  0.0   // 底部左側
];

// 索引數據
const indices = [
0, 1, 2,  // 第一個三角形
0, 2, 3   // 第二個三角形
];

// 創建並綁定頂點緩衝區
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

// 創建並綁定索引緩衝區
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);

// 設置屬性指針
const positionAttributeLocation = gl.getAttribLocation(program, 'a_position');
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 3, gl.FLOAT, false, 0, 0);

// 繪製正方形
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);

在這個範例中,我們定義了四個頂點來構成我們的正方形,並使用索引來指定這些頂點應如何連接以形成兩個三角形。我們創建了頂點緩衝區和索引緩衝區,設置了屬性指針,然後調用 drawElements() 來渲染我們的正方形。

必要操作:成功的秘訣

要在 WebGL 中成功繪製一個模型,我們需要遵循一些關鍵步驟。可以把這看作是一個美味 3D 圖形蛋糕的配方!

WebGL 繪製清單

  1. 創建緩衝區:設置頂點和索引緩衝區來存儲你的模型數據。
  2. 編譯著色器:編寫並編譯頂點和片段著色器。
  3. 創建程序:將編譯好的著色器鏈接到一個程序中。
  4. 設置屬性指針:告訴 WebGL 如何解釋你的頂點數據。
  5. 設置統一變量:將任何必要的統一變量傳遞給你的著色器。
  6. 綁定緩衝區:激活你想要用來繪製的緩衝區。
  7. 繪製:調用 drawArrays()drawElements() 來渲染你的模型。

讓我們在以下更完整的範例中將它們全部整合起來:

// 頂點著色器
const vsSource = `
attribute vec4 a_position;
void main() {
gl_Position = a_position;
}
`;

// 片段著色器
const fsSource = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);  // 紅色
}
`;

// 編譯著色器函數
function compileShader(gl, source, type) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
return shader;
}

// 創建程序函數
function createProgram(gl, vertexShader, fragmentShader) {
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
return program;
}

// 主繪製函數
function drawModel(gl) {
// 編譯著色器
const vertexShader = compileShader(gl, vsSource, gl.VERTEX_SHADER);
const fragmentShader = compileShader(gl, fsSource, gl.FRAGMENT_SHADER);

// 創建程序
const program = createProgram(gl, vertexShader, fragmentShader);
gl.useProgram(program);

// 創建緩衝區並設置數據(如之前範例所示)
// ...

// 設置屬性指針
const positionAttributeLocation = gl.getAttribLocation(program, 'a_position');
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 3, gl.FLOAT, false, 0, 0);

// 繪製
gl.drawArrays(gl.TRIANGLES, 0, 3);  // 或者使用 gl.drawElements() 繪製索引幾何
}

這個範例將所有繪製模型所需的操作整合在一起。我們編譯著色器,創建程序,設置緩衝區和屬性指針,然後繪製我們的模型。

結論

恭喜你!你剛剛踏入了 WebGL 令人驚奇的世界。記住,就像學習任何新技能一樣,精通 WebGL 需要練習和耐心。如果第一次事情並不完美,不要氣餒——即使是經驗最豐富的圖形編程師有時也會意外繪製出粉紅色立方體而不是雄偉的龍!

繼續實驗,持續學習,最重要的是,享受其中。在你意識到之前,你將會在網頁瀏覽器中創造出令人驚艷的 3D 世界。祝編程愉快,未來的 3D 藝術家!

Credits: Image by storyset