WebGL - Shaders: Hướng dẫn cho người mới bắt đầu

Xin chào các bạn học lập trình! Hôm nay, chúng ta sẽ bắt đầu một chuyến hành trình thú vị vào thế giới của WebGL Shaders. Đừng lo lắng nếu bạn chưa bao giờ viết một dòng mã trước đây - tôi sẽ là người hướng dẫn thân thiện của bạn qua khu vực đầy màu sắc này của đồ họa máy tính.

WebGL - Shaders

Shaders là gì?

Trước khi chúng ta đi sâu vào, hãy hiểu shaders là gì. Hãy tưởng tượng bạn đang vẽ một bức tranh. Bức vải là màn hình máy tính của bạn, và shaders giống như những cọ vẽ ma thuật giúp máy tính biết cách để màu cho từng điểm ảnh. Đ酷, phải không?

Kiểu dữ liệu

Trong thế giới của shaders, chúng ta có một số kiểu dữ liệu đặc biệt để làm việc. Hãy nhìn vào chúng:

Kiểu dữ liệu Mô tả Ví dụ
float Một số float có độ chính xác đơn 3.14
vec2 Một vector 2D vec2(1.0, 2.0)
vec3 Một vector 3D vec3(1.0, 2.0, 3.0)
vec4 Một vector 4D vec4(1.0, 2.0, 3.0, 4.0)
mat2 Một ma trận 2x2 mat2(1.0, 2.0, 3.0, 4.0)
mat3 Một ma trận 3x3 mat3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)
mat4 Một ma trận 4x4 mat4(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0)

Đừng lo lắng nếu những điều này có vẻ quá tải - chúng ta sẽ sử dụng chúng từng bước!

Định ngữ

Định ngữ giống như những nhãn đặc biệt chúng ta đặt lên các biến của mình. Chúng cho biết shader cần xử lý các biến này như thế nào. Dưới đây là những định ngữ chính:

Định ngữ Mô tả
attribute Giá trị đầu vào thay đổi theo đỉnh
uniform Giá trị đầu vào không thay đổi cho tất cả các đỉnh
varying Giá trị được truyền từ shader đỉnh đến shader điểm ảnh

Shader đỉnh

Shader đỉnh giống như xương sống của mô hình 3D của chúng ta. Nó tính toán vị trí của từng điểm (đỉnh) của mô hình trên màn hình. Dưới đây là một shader đỉnh đơn giản:

attribute vec3 aVertexPosition;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;

void main(void) {
gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aVertexPosition, 1.0);
}

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

  1. Chúng ta khai báo một attribute có tên aVertexPosition - đây là vị trí của đỉnh của chúng ta.
  2. Chúng ta có hai ma trận uniform - những ma trận này giúp chúng ta định vị và chiếu mô hình 3D của chúng ta lên màn hình 2D.
  3. Trong hàm main, chúng ta tính toán vị trí cuối cùng của đỉnh của chúng ta.

Shader điểm ảnh

Nếu shader đỉnh là xương sống, thì shader điểm ảnh là da. Nó quyết định màu sắc của từng điểm ảnh. Dưới đây là một shader điểm ảnh đơn giản:

precision mediump float;

void main(void) {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

Shader này đang sơn mọi thứ thành màu đỏ! vec4(1.0, 0.0, 0.0, 1.0) đại diện cho màu đỏ tối đa, không có xanh lá cây, không có xanh lam và độ trong suốt tối đa.

Lưu trữ và biên dịch các chương trình shader

Bây giờ chúng ta đã viết xong các shader, chúng ta cần thông báo cho WebGL về chúng. Dưới đây là cách chúng ta làm điều đó trong JavaScript:

function getShader(gl, id) {
const shaderScript = document.getElementById(id);
if (!shaderScript) return null;

const str = shaderScript.text;
let shader;

if (shaderScript.type === "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type === "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}

gl.shaderSource(shader, str);
gl.compileShader(shader);

if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}

return shader;
}

Hàm này thực hiện một số điều:

  1. Nó tìm mã shader của chúng ta trong tài liệu HTML.
  2. Nó tạo một shader của đúng loại (điểm ảnh hoặc đỉnh).
  3. Nó biên dịch shader và kiểm tra lỗi.

Chương trình kết hợp

Cuối cùng, chúng ta cần kết hợp shader đỉnh và shader điểm ảnh thành một chương trình:

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

if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialize shaders");
}

gl.useProgram(shaderProgram);

Mã này tạo một chương trình, gắn các shader vào chương trình, liên kết chương trình và thông báo WebGL sử dụng nó.

Và thế là xong! Bạn đã chính thức bước vào thế giới của WebGL shaders. Nhớ rằng, giống như học bất kỳ ngôn ngữ mới nào, nó cần thời gian để thực hành. Đừng nản lòng nếu nó không ngay lập tức hiểu - tiếp tục thử nghiệm và sớm bạn sẽ tạo ra những hình ảnh 3D tuyệt vời trong trình duyệt web của mình!

Trong những năm dạy học của tôi, tôi đã thấy biết bao nhiêu học sinh từ người mới bắt đầu trở thành những pháp sư shader. Một trong những học sinh của tôi thậm chí đã sử dụng kỹ năng này để tạo ra một bảo tàng nghệ thuật ảo cho dự án cuối khóa - hãy tưởng tượng đi qua một bảo tàng 3D ngay trong trình duyệt web của bạn!

Vậy, bạn sẽ tạo ra điều gì với kỹ năng shader mới của mình? Giới hạn duy nhất là trí tưởng tượng của bạn! Chúc mừng bạn, những nhà đồ họa tương lai!

Credits: Image by storyset