WebGL - Translation: Moving Objects in 3D Space
Xin chào các nhà phát triển WebGL đang trên đà trở thành chuyên gia! 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. Chúng ta sẽ khám phá khái niệm dịch chuyển trong WebGL, mà cơ bản là một cách nói hoa mỹ để nói "di chuyển các vật thể xung quanh." Đến cuối bài hướng dẫn này, bạn sẽ có khả năng làm cho các vật thể nhảy múa trên màn hình như một vũ điệu số! Hãy cùng bắt đầu!
What is Translation in WebGL? (Gì là dịch chuyển trong WebGL?)
Trước khi chúng ta bắt đầu dịch chuyển các tam giác như những quân cờ vua, hãy hiểu dịch chuyển thực sự có nghĩa là gì trong bối cảnh đồ họa máy tính.
The Basics of Translation (Cơ bản về dịch chuyển)
Dịch chuyển là quá trình di chuyển một vật thể từ vị trí này sang vị trí khác trong không gian 2D hoặc 3D. Nó giống như việc bạn nhấc một ly từ bàn và đặt nó lên kệ. Ly (vật thể của chúng ta) đã di chuyển từ vị trí ban đầu sang vị trí mới.
Trong WebGL, chúng ta sử dụng toán học để đạt được sự di chuyển này. Đừng lo nếu bạn không phải là một thiên tài toán học - WebGL đã làm phần lớn công việc nặng nhọc cho chúng ta!
Why is Translation Important? (Tại sao dịch chuyển lại quan trọng?)
Hãy tưởng tượng một trò chơi video mà các nhân vật không thể di chuyển, hoặc một phần mềm mô hình 3D mà các vật thể bị kẹt ở một chỗ. Rất nhàm chán, phải không? Dịch chuyển cho phép chúng ta tạo ra đồ họa động, tương tác mà phản ứng với đầu vào của người dùng hoặc theo các animation đã xác định.
Steps to Translate a Triangle (Các bước để dịch chuyển một tam giác)
Bây giờ chúng ta đã hiểu dịch chuyển là gì, hãy phân tích quá trình di chuyển một tam giác đơn giản trong WebGL. Chúng ta sẽ làm này bước một bước một, để bạn có thể dễ dàng theo dõi.
Step 1: Define Your Triangle (Xác định tam giác của bạn)
Đầu tiên, chúng ta cần tạo tam giác của mình. Trong WebGL, chúng ta xác định các hình dạng bằng các đỉnh (các điểm góc). Dưới đây là cách chúng ta có thể xác định một tam giác đơn giản:
const vertices = [
0.0, 0.5, // Đỉnh trên
-0.5, -0.5, // Đỉnh dưới bên trái
0.5, -0.5 // Đỉnh dưới bên phải
];
Điều này tạo ra một tam giác với đỉnh trên ở (0, 0.5) và các góc پای dưỡ ở (-0.5, -0.5) và (0.5, -0.5).
Step 2: Create a Translation Matrix (Tạo ma trận dịch chuyển)
Để dịch chuyển tam giác của chúng ta, chúng ta cần tạo một ma trận dịch chuyển. Ma trận này cho WebGL biết cần di chuyển vật thể của chúng ta bao nhiêu theo mỗi trục (x, y, và z). Dưới đây là cách chúng ta tạo một ma trận dịch chuyển:
const translationMatrix = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
tx, ty, 0, 1
];
Trong đó tx
và ty
là số lượng chúng ta muốn di chuyển theo các trục x và y tương ứng.
Step 3: Apply the Translation in the Vertex Shader (Áp dụng dịch chuyển trong vertex shader)
Bây giờ đến phần thú vị! Chúng ta cần sửa đổi vertex shader của mình để áp dụng dịch chuyển. Dưới đây là một vertex shader đơn giản bao gồm dịch chuyển:
attribute vec2 a_position;
uniform mat4 u_translation;
void main() {
gl_Position = u_translation * vec4(a_position, 0, 1);
}
Shader này lấy mỗi vị trí đỉnh, chuyển đổi nó thành một vector 4D (cần thiết cho phép nhân ma trận), và sau đó nhân nó với ma trận dịch chuyển.
Step 4: Update the Translation Values (Cập nhật giá trị dịch chuyển)
Để làm cho tam giác của chúng ta di chuyển, chúng ta cần cập nhật các giá trị dịch chuyển theo từng thời điểm. Chúng ta có thể làm điều này trong mã JavaScript của mình:
function updateAndDraw() {
tx += 0.01; // Di chuyển sang phải
ty += 0.005; // Di chuyển lên trên
// Cập nhật ma trận dịch chuyển
gl.uniformMatrix4fv(translationLocation, false, translationMatrix);
// Vẽ tam giác
gl.drawArrays(gl.TRIANGLES, 0, 3);
requestAnimationFrame(updateAndDraw);
}
Hàm này cập nhật các giá trị dịch chuyển của chúng ta, gửi ma trận mới đến GPU, và sau đó vẽ lại tam giác. Gọi requestAnimationFrame
đảm bảo rằng điều này xảy ra mượt mà, mỗi khung hình.
Example – Translate a Triangle (Ví dụ - Dịch chuyển một tam giác)
Hãy kết hợp tất cả lại với nhau trong một ví dụ hoàn chỉnh. Mã này sẽ tạo một tam giác di chuyển斜 đối角 qua màn hình:
// Vertex shader
const vertexShaderSource = `
attribute vec2 a_position;
uniform mat4 u_translation;
void main() {
gl_Position = u_translation * vec4(a_position, 0, 1);
}
`;
// Fragment shader
const fragmentShaderSource = `
precision mediump float;
void main() {
gl_FragColor = vec4(1, 0, 0, 1); // Màu đỏ
}
`;
// Khởi tạo WebGL
const canvas = document.getElementById('glcanvas');
const gl = canvas.getContext('webgl');
// Tạo và biên dịch shaders
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
// Tạo chương trình
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
// Tạo bộ nhớ đệm và tải dữ liệu đỉnh
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
const positions = [
0.0, 0.5,
-0.5, -0.5,
0.5, -0.5
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
// Thiết lập thuộc tính
const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
// Thiết lập.uniform
const translationLocation = gl.getUniformLocation(program, "u_translation");
// Biến dịch chuyển
let tx = 0;
let ty = 0;
function updateAndDraw() {
// Xóa canvas
gl.clear(gl.COLOR_BUFFER_BIT);
// Cập nhật dịch chuyển
tx += 0.01;
ty += 0.005;
// Tạo ma trận dịch chuyển
const translationMatrix = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
tx, ty, 0, 1
];
// Gửi ma trận đến shader
gl.uniformMatrix4fv(translationLocation, false, translationMatrix);
// Vẽ
gl.drawArrays(gl.TRIANGLES, 0, 3);
// Yêu cầu khung hình tiếp theo
requestAnimationFrame(updateAndDraw);
}
// Bắt đầu animation
updateAndDraw();
Mã này tạo một tam giác đỏ di chuyển斜 đối角 qua màn hình. Dưới đây là những gì đang xảy ra:
- Chúng ta xác định các shaders, bao gồm ma trận dịch chuyển.
- Chúng ta thiết lập WebGL, tạo chương trình và tải các đỉnh tam giác.
- Chúng ta tạo các biến dịch chuyển (tx và ty).
- Trong hàm
updateAndDraw
, chúng ta:
- Xóa canvas
- Cập nhật các giá trị dịch chuyển
- Tạo ma trận dịch chuyển mới
- Gửi ma trận này đến GPU
- Vẽ tam giác
- Yêu cầu khung hình tiếp theo
Và voilà! Bạn đã tạo ra một tam giác di chuyển trong WebGL. Chúc mừng!
Conclusion (Kết luận)
Dịch chuyển trong WebGL có thể trông phức tạp ban đầu, nhưng thực sự chỉ là về việc di chuyển các vật thể xung quanh một cách thông minh. Chúng ta đã bao gồm các khái niệm cơ bản ở đây, nhưng có rất nhiều điều bạn có thể làm với dịch chuyển - kết hợp nó với quay và缩放, tạo animation phức tạp, hoặc thậm chí xây dựng các môi trường 3D tương tác.
Nhớ rằng, mọi hành trình đều bắt đầu từ một bước đầu tiên - hoặc trong trường hợp của chúng ta, một bước dịch chuyển của tam giác. Hãy tiếp tục thực hành, tiếp tục thử nghiệm, và trước khi bạn biết, bạn sẽ tạo ra các đồ họa 3D di chuyển và tương tác theo những cách bạn không thể tưởng tượng.
Chúc mừng编码, và hy vọng các tam giác của bạn luôn tìm thấy con đường về nhà!
Credits: Image by storyset