WebGL: Hướng dẫn cơ bản về đồ họa 3D trong trình duyệt

Xin chào các pháp sư đồ họa 3D tương lai! Tôi rất vui mừng được làm hướng dẫn viên cho bạn trong hành trình đầy.exciting này vào thế giới của WebGL. Là một ai đó đã dạy đồ họa máy tính trong nhiều năm, tôi có thể告诉 bạn rằng WebGL giống như một枝魔法杖 cho trình duyệt của bạn. Nó cho phép bạn tạo ra những hình ảnh và动画 3D tuyệt đẹp ngay trong các trang web của bạn. Có phải đó là điều tuyệt vời không? Hãy cùng nhau khám phá!

WebGL - Home

WebGL là gì?

WebGL, viết tắt của Web Graphics Library, là một API JavaScript cho phép bạn render đồ họa 2D và 3D tương tác trong bất kỳ trình duyệt nào tương thích mà không cần cài đặt plugin. Nó giống như赐 cho trình duyệt của bạn siêu năng lực để tạo ra những trải nghiệm thị giác tuyệt vời!

Lịch sử ngắn gọn

WebGL được giới thiệu lần đầu tiên vào năm 2011, và từ那时, nó đã cách mạng hóa cách chúng ta nghĩ về đồ họa trên web. Trước WebGL, nếu bạn muốn tạo đồ họa 3D trong trình duyệt, bạn sẽ cần phụ thuộc vào các plugin như Flash hoặc Java applets. Bây giờ, với WebGL, chúng ta có thể làm tất cả những điều này một cách nguyên bản trong trình duyệt. Nó giống như chúng ta đã nâng cấp từ xe đạp lên xe thể thao!

Tiền đề

Trước khi bắt đầu hành trình WebGL của chúng ta, hãy chắc chắn rằng chúng ta có những công cụ đúng đắn trong hành trang:

  1. Một trình duyệt hiện đại (Chrome, Firefox, Safari hoặc Edge)
  2. Một编辑器 văn bản (Tôi khuyên dùng Visual Studio Code, nhưng bất kỳ编辑器 nào cũng được)
  3. Kiến thức cơ bản về HTML và JavaScript (Đừng lo nếu bạn quên, chúng ta sẽ ôn lại khi cần)

Bắt đầu với WebGL

Hãy tạo chương trình WebGL đầu tiên của chúng ta! Chúng ta sẽ bắt đầu với một ví dụ đơn giản "Hello, WebGL!" hiển thị một tam giác có màu trên màn hình.

Bước 1: Thiết lập HTML

Đầu tiên, chúng ta cần tạo một tệp HTML với phần tử canvas. Canvas này là nơi mà魔法 WebGL của chúng ta sẽ diễn ra.

<!DOCTYPE html>
<html lang="vi">
<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>

Trong HTML này, chúng ta đã tạo một phần tử canvas với ID là "glCanvas" và đặt kích thước của nó là 640x480 pixel. Chúng ta cũng đã liên kết đến một tệp JavaScript tên là "webgl-demo.js" nơi chúng ta sẽ viết mã WebGL của mình.

Bước 2: Khởi tạo WebGL

Bây giờ, hãy tạo tệp "webgl-demo.js" và bắt đầu viết một số JavaScript để khởi tạo WebGL:

function main() {
const canvas = document.getElementById("glCanvas");
const gl = canvas.getContext("webgl");

if (!gl) {
alert("Không thể khởi tạo WebGL. Trình duyệt hoặc máy tính của bạn có thể không hỗ trợ.");
return;
}

// Đặt màu nền là đen, hoàn toàn không trong suốt
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// Xóa bộ nhớ đệm màu với màu đã đặt
gl.clear(gl.COLOR_BUFFER_BIT);
}

window.onload = main;

Hãy phân tích này:

  1. Chúng ta lấy tham chiếu đến phần tử canvas.
  2. Chúng ta cố gắng lấy ngữ cảnh WebGL từ canvas. Nếu thất bại, nó có nghĩa là WebGL không được hỗ trợ, và chúng ta hiển thị thông báo lỗi.
  3. Nếu thành công, chúng ta đặt màu nền (màu nền) là đen và xóa canvas.

Bước 3: Tạo Shaders

Shaders là các chương trình đặc biệt chạy trên GPU. Chúng được viết bằng ngôn ngữ GLSL (OpenGL Shading Language). Chúng ta cần hai loại shaders: vertex shaders và fragment shaders.

// Chương trình vertex shader
const vsSource = `
attribute vec4 aVertexPosition;

void main() {
gl_Position = aVertexPosition;
}
`;

// Chương trình fragment shader
const fsSource = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;

Vertex shader định vị các đỉnh của chúng ta, trong khi fragment shader màu các điểm ảnh (trong trường hợp này, màu đỏ).

Bước 4: Khởi tạo chương trình Shader

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

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

return shader;
}

Mã này biên dịch các shaders của chúng ta, liên kết chúng thành một chương trình, và kiểm tra xem có lỗi nào không.

Bước 5: Tạo Tam giác

Bây giờ, hãy tạo dữ liệu cho tam giác của chúng ta:

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

Điều này tạo một bộ nhớ đệm và điền nó với vị trí của các đỉnh tam giác của chúng ta.

Bước 6: Vẽ cảnh

Cuối cùng, hãyputting tất cả lại với nhau và vẽ tam giác của chúng ta:

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 thành phần mỗi lần lặp
gl.FLOAT, // dữ liệu là số float 32bit
false,    // không chuẩn hóa
0,        // bước (0 = tự động)
0         // offset vào bộ nhớ đệm
);

gl.drawArrays(gl.TRIANGLES, 0, 3);
}

Hàm này xóa canvas, thiết lập chương trình shader, kết nối dữ liệu bộ nhớ đệm, và cuối cùng vẽ tam giác.

Kết hợp tất cả lại

Bây giờ, hãy cập nhật hàm main của chúng ta để sử dụng tất cả các mảnh ghép:

function main() {
const canvas = document.getElementById("glCanvas");
const gl = canvas.getContext("webgl");

if (!gl) {
alert("Không thể khởi tạo WebGL. Trình duyệt hoặc máy tính của bạn có thể không hỗ trợ.");
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;

Và thế là xong! Chương trình WebGL đầu tiên của bạn. Khi bạn mở tệp HTML trong trình duyệt, bạn nên thấy một tam giác đỏ trên nền đen. Chúc mừng!

Các phương thức WebGL phổ biến

Dưới đây là bảng một số phương thức WebGL phổ biến chúng ta đã sử dụng và mục đích của chúng:

Phương thức Mục đích
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() Khởi tạo và tạo bộ nhớ đệm dữ liệu
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() Liên kết một shader với một chương trình
gl.linkProgram() Liên kết một chương trình
gl.useProgram() Đặt chương trình đã chỉ định làm phần của trạng thái render hiện tại
gl.getAttribLocation() Trả về vị trí của một biến attribute
gl.enableVertexAttribArray() Bật một mảng vertex attribute
gl.vertexAttribPointer() Chỉ định cách bố trí dữ liệu vertex attribute
gl.drawArrays() Render các primitive từ dữ liệu mảng

Kết luận

Wow, chúng ta đã đi qua rất nhiều nội dung hôm nay! Chúng ta đã học về WebGL là gì, thiết lập môi trường phát triển, và tạo ra chương trình WebGL đầu tiên của chúng ta. Nhớ rằng, học WebGL giống như học骑自行车 - ban đầu có thể trông lurching, nhưng với sự luyện tập, bạn sẽ nhanh chóng zooming xung quanh!

Trong các bài học tiếp theo, chúng ta sẽ khám phá các hình dạng phức tạp hơn, thêm tính tương tác, và thậm chí chìm vào đồ họa 3D. Thế giới của WebGL là rộng lớn và đầy thú vị, và tôi không thể đợi để khám phá thêm với bạn. Hẹn gặp lại lần sau, chúc bạn vui vẻ với mã code!

Credits: Image by storyset