WebGL - xoay: Mang Đồ họa Của Bạn Sống Động

Xin chào, các bạn phát triển WebGL triển vọng! Hôm nay, chúng ta sẽ cùng nhau khám phá một trong những khía cạnh thú vị nhất của đồ họa máy tính: xoay. Như một giáo viên khoa học máy tính thân thiện trong khu phố của bạn, tôi ở đây để hướng dẫn bạn qua thế giới kỳ diệu của các tam giác quay và các hình ảnh quay cuồng. Vậy, hãy đeo cặp kính 3D giả tưởng của bạn, và chúng ta cùng bắt đầu nhé!

WebGL - Rotation

Hiểu về xoay trong WebGL

Trước khi chúng ta nhảy vào mã, hãy dành một chút thời gian để hiểu xem xoay có nghĩa là gì trong ngữ cảnh của WebGL. Hãy tưởng tượng bạn đang cầm một chiếc máy bay giấy. Khi bạn quay nó, bạn đang thay đổi hướng của nó trong không gian. Trong WebGL, chúng ta làm điều tương tự, nhưng với độ chính xác toán học!

Xoay trong WebGL liên quan đến việc thay đổi vị trí của các đỉnh (các điểm tạo nên hình dạng của chúng ta) xung quanh một trục trung tâm. Điều này có thể là trục X, Y, hoặc Z, hoặc thậm chí là sự kết hợp của chúng.

Phép màu của Ma trận

Bây giờ, tôi biết bạn đang nghĩ gì: "Ma trận? Đó có phải là thứ gì từ các bộ phim 'The Matrix' không?" Well, không phải vậy, nhưng chúng cũng rất tuyệt vời! Trong WebGL, chúng ta sử dụng ma trận để thực hiện xoay một cách hiệu quả. Đừng lo nếu điều này có vẻ phức tạp - chúng ta sẽ giải thích từng bước.

Ví dụ - Xoay một Tam giác

Hãy bắt đầu với một ví dụ đơn giản: xoay một tam giác. Chúng ta sẽ bắt đầu với một tam giác cơ bản và sau đó làm cho nó quay như một vũ công hình học!

Bước 1: Thiết lập Môi trường WebGL của Chúng ta

Trước tiên, chúng ta cần thiết lập ngữ cảnh WebGL. Dưới đây là cấu trúc HTML cơ bản:

<canvas id="glCanvas" width="640" height="480"></canvas>
<script>
// Mã WebGL của chúng ta sẽ nằm ở đây
</script>

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

Bây giờ, hãy khởi tạo WebGL:

const canvas = document.getElementById('glCanvas');
const gl = canvas.getContext('webgl');

if (!gl) {
console.error('WebGL không được hỗ trợ');
return;
}

Mã này lấy phần tử canvas và cố gắng lấy ngữ cảnh WebGL. Nếu WebGL không được hỗ trợ, chúng ta sẽ thấy một thông báo lỗi.

Bước 3: Tạo Shaders của Chúng ta

Shaders là các chương trình đặc biệt chạy trên GPU. Chúng ta cần hai loại: vertex shaders và fragment shaders. Dưới đây là một bộ đơn giản:

const vertexShaderSource = `
attribute vec2 a_position;
uniform mat3 u_matrix;
void main() {
gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);
}
`;

const fragmentShaderSource = `
precision mediump float;
void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}
`;

Vertex shader áp dụng ma trận xoay của chúng ta, trong khi fragment shader chỉ đơn giản là màu đỏ cho tam giác của chúng ta.

Bước 4: Biên dịch và Kết nối Shaders

Tiếp theo, chúng ta cần biên dịch và kết nối các shaders của mình:

function createShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
return shader;
}

const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);

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

Mã này tạo chương trình shader của chúng ta, mà chúng ta sẽ sử dụng để render tam giác quay của mình.

Bước 5: Tạo Tam giác của Chúng ta

Bây giờ, hãy xác định tam giác của chúng ta:

const positions = [
0, 0.5,
-0.5, -0.5,
0.5, -0.5
];

const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

Điều này tạo một tam giác đơn giản được đặt tại gốc tọa độ.

Bước 6: Phép màu của Xoay

Đây là nơi phép màu thực sự xảy ra. Chúng ta sẽ tạo một hàm để sinh ra ma trận xoay:

function createRotationMatrix(angleInRadians) {
const c = Math.cos(angleInRadians);
const s = Math.sin(angleInRadians);
return [
c, -s, 0,
s, c, 0,
0, 0, 1
];
}

Hàm này nhận một góc theo radian và trả về một ma trận xoay 3x3.

Bước 7: Render Tam giác Quay của Chúng ta

Cuối cùng, hãy kết hợp tất cả lại và làm cho tam giác của chúng ta quay:

let angleInRadians = 0;

function render() {
angleInRadians += 0.01;

gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);

gl.useProgram(program);

const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
gl.enableVertexAttribArray(positionAttributeLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);

const matrixLocation = gl.getUniformLocation(program, "u_matrix");
const matrix = createRotationMatrix(angleInRadians);
gl.uniformMatrix3fv(matrixLocation, false, matrix);

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

requestAnimationFrame(render);
}

render();

Hàm này thực hiện nhiều việc:

  1. Tăng góc xoay của chúng ta
  2. Xóa canvas
  3. Thiết lập chương trình shader và các thuộc tính
  4. Tạo và áp dụng ma trận xoay
  5. Vẽ tam giác
  6. Yêu cầu khung hình tiếp theo

Và voilà! Chúng ta có một tam giác quay!

Kết luận

Chúc mừng! Bạn vừa tạo ra hình dạng quay đầu tiên của mình trong WebGL. Nhớ rằng, đây chỉ là bắt đầu. Với những nguyên tắc cơ bản này, bạn có thể tạo ra các cảnh 3D phức tạp với nhiều đối tượng quay.

Khi chúng ta kết thúc, tôi nhớ lại một học sinh曾经说过, "Tôi nghĩ rằng đồ họa máy tính chỉ là về phần mềm sang trọng, nhưng bây giờ tôi thấy nó giống như một người Puppeteer kỹ thuật số!" Và cô ấy đã đúng - với WebGL, bạn đang kéo các sợi dây của chính mình trong buổi biểu diễn Puppeteer kỹ thuật số.

Tiếp tục thực hành, tiếp tục thí nghiệm, và quan trọng nhất, tiếp tục vui vẻ với WebGL. Trước khi bạn biết điều đó, bạn sẽ tạo ra các visualization 3D ấn tượng sẽ làm cho ngay cả những nhà phát triển có kinh nghiệm phải nói "Wow!"

Phương thức Mô tả
createShader(gl, type, source) Tạo và biên dịch một shader
createRotationMatrix(angleInRadians) Sinh ra một ma trận xoay 2D
render() Render tam giác quay
gl.clearColor(r, g, b, a) Đặt màu để xóa canvas
gl.clear(gl.COLOR_BUFFER_BIT) Xóa canvas
gl.useProgram(program) Đặt chương trình shader hiện tại
gl.getAttribLocation(program, name) Lấy vị trí của một thuộc tính
gl.enableVertexAttribArray(location) Kích hoạt một mảng thuộc tính
gl.bindBuffer(gl.ARRAY_BUFFER, buffer) Đính kèm một buffer
gl.vertexAttribPointer(location, size, type, normalized, stride, offset) Xác định bố cục của dữ liệu đỉnh
gl.getUniformLocation(program, name) Lấy vị trí của một biến đồng nhất
gl.uniformMatrix3fv(location, transpose, value) Đặt giá trị ma trận đồng nhất
gl.drawArrays(mode, first, count) Vẽ primitives từ dữ liệu mảng
requestAnimationFrame(callback) Yêu cầu khung hình tiếp theo

Chúc mừng coding, và hy vọng rằng các tam giác của bạn luôn quay đúng hướng!

Credits: Image by storyset