WebGL - 魔方旋轉

你好,未來的WebGL大師們!今天,我們將踏上一段令人興奮的旅程,進入3D圖形的世界。在本教程結束時,你將能夠使用WebGL創建一個旋轉的魔方。這不是很酷嗎?讓我們一起來看看!

WebGL - Cube Rotation

了解基礎知識

在我們開始像DJ一樣旋轉魔方之前,讓我們先了解一下一些基本概念。

什么是WebGL?

WebGL(Web圖形庫)是一個JavaScript API,讓我們能在網頁瀏覽器中渲染3D圖形。這就像是給你的瀏覽器一副3D眼鏡!

為什麼選擇魔方?

你可能會想,"我們為什麼從魔方開始?" 嘿,親愛的學生們,魔方就像是3D圖形的"Hello World"。它足夠簡單,讓我們能夠理解,但同時也足夠複雜,教導我們重要的概念。而且,有誰不愛一個好魔方呢?

設置我們的WebGL環境

HTML畫布

首先,我們需要一個舞台,讓我們的魔方在上面表演。在WebGL中,這個舞台叫做畫布。讓我們來設定它:

<canvas id="glcanvas" width="640" height="480">
你的瀏覽器不支持HTML5畫布
</canvas>

這會創建一個640x480像素的畫布。如果你看不到它,別擔心 - 現在它就像是一個無形的舞池。

初始化WebGL

現在,讓我們讓WebGL準備好開始派對:

var canvas = document.getElementById('glcanvas');
var gl = canvas.getContext('webgl');

if (!gl) {
console.log('WebGL不支持,轉而使用experimental-webgl');
gl = canvas.getContext('experimental-webgl');
}

if (!gl) {
alert('你的瀏覽器不支持WebGL');
}

這段代碼獲取我們的WebGL環境。如果你的瀏覽器不支持WebGL,那就好比在VHS播放器上播放DVD - 根本行不通!

創建我們的3D魔方

定義頂點

魔方有8個角落(頂點)。我們需要告訴WebGL這些角落在哪里:

var vertices = [
// 正面
-1.0, -1.0,  1.0,
1.0, -1.0,  1.0,
1.0,  1.0,  1.0,
-1.0,  1.0,  1.0,

// 背面
-1.0, -1.0, -1.0,
-1.0,  1.0, -1.0,
1.0,  1.0, -1.0,
1.0, -1.0, -1.0,

// 顶面
-1.0,  1.0, -1.0,
-1.0,  1.0,  1.0,
1.0,  1.0,  1.0,
1.0,  1.0, -1.0,

// 底面
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0,  1.0,
-1.0, -1.0,  1.0,

// 右面
1.0, -1.0, -1.0,
1.0,  1.0, -1.0,
1.0,  1.0,  1.0,
1.0, -1.0,  1.0,

// 左面
-1.0, -1.0, -1.0,
-1.0, -1.0,  1.0,
-1.0,  1.0,  1.0,
-1.0,  1.0, -1.0
];

每一組三個數字代表我們魔方的一個角落在三維空間中的位置。這就像是給WebGL一張我們魔方的地圖!

創建緩存

現在,我們需要把這些數據發送到GPU:

var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

這就像是把我们的魔方打包進一個行李箱(緩存)然後發送到GPU。

Shaders - WebGL的魔法師

頂點Shader

頂點Shader負責定位我們的頂點:

var vertexShaderSource = `
attribute vec3 aVertexPosition;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
void main(void) {
gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aVertexPosition, 1.0);
}
`;

這個Shader將每個頂點和我們的變換矩陣應用到一起。這就像是魔法師移動我們魔方的角落!

片段Shader

片段Shader負責給我們的魔方上色:

var fragmentShaderSource = `
void main(void) {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
`;

這個簡單的Shader將所有東西染成白色。這就像是給我们的魔方上了色!

編譯和鏈接Shaders

現在我們需要編譯我們的Shaders並將它們鏈接到一個程序中:

function getShader(gl, source, type) {
var shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);

if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert('編譯Shader時發生錯誤:' + gl.getShaderInfoLog(shader));
return null;
}

return shader;
}

var vertexShader = getShader(gl, vertexShaderSource, gl.VERTEX_SHADER);
var fragmentShader = getShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER);

var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);

if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('無法初始化Shader程序:' + gl.getProgramInfoLog(shaderProgram));
}

gl.useProgram(shaderProgram);

這就像是教導我們的魔法師(Shaders)他們的技巧,然後把他們放到舞台上!

讓我們的魔方旋轉

設置旋轉

要讓我們的魔方旋轉,我們需要在時間上更新它的旋轉角度:

var cubeRotation = 0.0;

function render(now) {
now *= 0.001;  // 轉換為秒
const deltaTime = now - then;
then = now;

cubeRotation += deltaTime;

drawScene();

requestAnimationFrame(render);
}

這個函數會被反覆調用,每次更新我們魔方的旋轉。

繪製場景

現在讓我們把所有東西合起來,繪製我們旋轉的魔方:

function drawScene() {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

const projectionMatrix = mat4.create();
mat4.perspective(projectionMatrix, 45 * Math.PI / 180, gl.canvas.clientWidth / gl.canvas.clientHeight, 0.1, 100.0);

const modelViewMatrix = mat4.create();
mat4.translate(modelViewMatrix, modelViewMatrix, [-0.0, 0.0, -6.0]);
mat4.rotate(modelViewMatrix, modelViewMatrix, cubeRotation, [0, 1, 1]);

gl.uniformMatrix4fv(gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'), false, projectionMatrix);
gl.uniformMatrix4fv(gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'), false, modelViewMatrix);

gl.drawArrays(gl.TRIANGLE_STRIP, 0, 36);
}

這個函數清除畫布,設置我們的視角,應用我們的旋轉,最後繪製我們的魔方。

結論

这就是了,各位!我們使用WebGL創建了一個旋轉的3D魔方。記住,掌握WebGL就像學習擲飛鏢 - 它需要練習,但一旦你掌握了它,你就能做出令人驚奇的事情!

這裡是一個我們使用的主要方法的總結:

方法 描述
gl.createBuffer() 創建一個新的緩存對象
gl.bindBuffer() 將緩存對象绑定到一個目標
gl.bufferData() 創建並初始化緩存對象的數據存儲
gl.createShader() 創建一個Shader對象
gl.shaderSource() 設置Shader對象的源代碼
gl.compileShader() 編譯Shader對象
gl.createProgram() 創建一個程序對象
gl.attachShader() 將Shader對象附加到程序對象
gl.linkProgram() 鏈接程序對象
gl.useProgram() 設置當前程序為當前渲染狀態的一部分
gl.clear() 清除緩存到預設值
gl.uniformMatrix4fv() 為當前程序指定一個4x4矩陣的值
gl.drawArrays() 從數組數據渲染原始

繼續練習,繼續編程,很快你就能在瀏覽器中創建出令人驚奇的3D圖形。編程愉快!

Credits: Image by storyset