WebGL - xoay khối lập phương

Xin chào các pháp sư WebGL tương lai! Hôm nay, chúng ta sẽ bắt đầu một chuyến hành trình đầy thú vị vào thế giới của đồ họa 3D. Cuối cùng của bài hướng dẫn này, bạn sẽ có khả năng tạo ra một khối lập phương xoay sử dụng WebGL. Có phải đó là điều tuyệt vời không? Hãy cùng bắt đầu!

WebGL - Cube Rotation

Hiểu về các nguyên tắc cơ bản

Trước khi chúng ta bắt đầu xoay khối lập phương như một DJ, hãy cùng tìm hiểu một số khái niệm cơ bản.

WebGL là gì?

WebGL (Web Graphics Library) là một API JavaScript cho phép chúng ta render đồ họa 3D trong trình duyệt web. Nó giống như tặng trình duyệt của bạn một cặp kính 3D!

Tại sao lại là khối lập phương?

Bạn có thể tự hỏi, "Tại sao chúng ta lại bắt đầu với khối lập phương?" Đúng vậy, các học sinh yêu quý của tôi, khối lập phương giống như "Hello World" của đồ họa 3D. Nó đơn giản đủ để hiểu nhưng phức tạp đủ để dạy chúng ta những khái niệm quan trọng. Thêm vào đó, ai mà không yêu thích một khối lập phương?

Thiết lập môi trường WebGL của chúng ta

HTML Canvas

Đầu tiên, chúng ta cần một sân khấu cho khối lập phương của mình để biểu diễn. Trong WebGL, sân khấu này được gọi là canvas. Hãy thiết lập nó:

<canvas id="glcanvas" width="640" height="480">
Trình duyệt của bạn không hỗ trợ HTML5 canvas
</canvas>

Điều này tạo ra một canvas 640x480 pixel. Nếu bạn không thể thấy nó, đừng lo lắng - nó giống như một sàn nhảy vô hình hiện tại.

Khởi tạo WebGL

Bây giờ, hãy chuẩn bị WebGL để sẵn sàng cho bữa tiệc:

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

if (!gl) {
console.log('WebGL không được hỗ trợ, chuyển sang experimental-webgl');
gl = canvas.getContext('experimental-webgl');
}

if (!gl) {
alert('Trình duyệt của bạn không hỗ trợ WebGL');
}

Mã này lấy ngữ cảnh WebGL của chúng ta. Nếu trình duyệt của bạn không hỗ trợ WebGL, nó giống như cố gắng phát DVD trên đầu máy VHS - nó sẽ không hoạt động!

Tạo khối lập phương 3D của chúng ta

Định nghĩa các đỉnh

Một khối lập phương có 8 góc (đỉnh). Chúng ta cần告诉 WebGL các góc này nằm ở đâu:

var vertices = [
// Mặt trước
-1.0, -1.0,  1.0,
1.0, -1.0,  1.0,
1.0,  1.0,  1.0,
-1.0,  1.0,  1.0,

// Mặt sau
-1.0, -1.0, -1.0,
-1.0,  1.0, -1.0,
1.0,  1.0, -1.0,
1.0, -1.0, -1.0,

// Mặt trên
-1.0,  1.0, -1.0,
-1.0,  1.0,  1.0,
1.0,  1.0,  1.0,
1.0,  1.0, -1.0,

// Mặt dưới
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0,  1.0,
-1.0, -1.0,  1.0,

// Mặt phải
1.0, -1.0, -1.0,
1.0,  1.0, -1.0,
1.0,  1.0,  1.0,
1.0, -1.0,  1.0,

// Mặt trái
-1.0, -1.0, -1.0,
-1.0, -1.0,  1.0,
-1.0,  1.0,  1.0,
-1.0,  1.0, -1.0
];

Mỗi bộ ba số đại diện cho một đỉnh của khối lập phương trong không gian 3D. Nó giống như cung cấp cho WebGL một bản đồ của khối lập phương của chúng ta!

Tạo bộ nhớ đệm

Bây giờ chúng ta cần gửi dữ liệu này đến GPU:

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

Điều này giống như đóng gói khối lập phương của chúng ta vào một vali (bộ nhớ đệm) và gửi nó đến GPU.

Shaders - Những pháp sư của WebGL

Vertex Shader

Vertex shader định vị các đỉnh của chúng ta:

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

Shader này lấy mỗi đỉnh và áp dụng các ma trận chuyển đổi. Nó giống như một pháp sư di chuyển các góc của khối lập phương của chúng ta!

Fragment Shader

Fragment shader màu cho khối lập phương của chúng ta:

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

Shader đơn giản này chỉ màu tất cả mọi thứ trắng. Nó giống như sơn khối lập phương của chúng ta!

Biên dịch và liên kết Shaders

Bây giờ chúng ta cần biên dịch các shader và liên kết chúng vào một chương trình:

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('Đã xảy ra lỗi khi biên dịch các 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('Không thể khởi tạo chương trình shader: ' + gl.getProgramInfoLog(shaderProgram));
}

gl.useProgram(shaderProgram);

Điều này giống như dạy các pháp sư (shaders) của chúng ta các tuyệt kỹ và sau đó đưa họ lên sân khấu!

Làm cho khối lập phương của chúng ta xoay

Thiết lập xoay

Để làm cho khối lập phương của chúng ta xoay, chúng ta cần cập nhật góc xoay của nó theo thời gian:

var cubeRotation = 0.0;

function render(now) {
now *= 0.001;  // chuyển đổi sang giây
const deltaTime = now - then;
then = now;

cubeRotation += deltaTime;

drawScene();

requestAnimationFrame(render);
}

Hàm này được gọi liên tục, cập nhật góc xoay của khối lập phương mỗi lần.

Vẽ cảnh

Bây giờ hãy kết hợp tất cả và vẽ khối lập phương xoay của chúng ta:

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);
}

Hàm này xóa canvas, thiết lập góc nhìn, áp dụng xoay và cuối cùng vẽ khối lập phương của chúng ta.

Kết luận

Và thế là bạn đã có nó, các bạn! Chúng ta đã tạo ra một khối lập phương 3D xoay sử dụng WebGL. Nhớ rằng, việc thành thạo WebGL giống như học chơi balle - nó cần sự tập luyện, nhưng một khi bạn đã thành thạo, bạn có thể làm những điều kỳ diệu!

Dưới đây là bảng tóm tắt các phương thức chính chúng ta đã sử dụng:

Phương thức Mô tả
gl.createBuffer() Tạo một bộ nhớ đệm mới
gl.bindBuffer() Liên kết một bộ nhớ đệm với một mục tiêu
gl.bufferData() Tạo và khởi tạo bộ nhớ lưu trữ của bộ nhớ đệm
gl.createShader() Tạo một đối tượng shader
gl.shaderSource() Đặt mã nguồn của một shader
gl.compileShader() Biên dịch một shader
gl.createProgram() Tạo một đối tượng chương trình
gl.attachShader() Gắn một shader vào một đối tượng chương trình
gl.linkProgram() Liên kết một đối tượng chương trình
gl.useProgram() Đặt đối tượng chương trình làm phần của trạng thái渲染 hiện tại
gl.clear() Xóa các bộ nhớ đệm để đặt chúng về giá trị mặc định
gl.uniformMatrix4fv() Xác định giá trị của một biến đồng nhất cho chương trình hiện tại
gl.drawArrays() Render các hình học từ dữ liệu mảng

Tiếp tục tập luyện, tiếp tục lập trình, và sớm bạn sẽ tạo ra những đồ họa 3D tuyệt vời trong trình duyệt của mình. Chúc các bạn may mắn!

Credits: Image by storyset