Kĩ năng mềm

Lập Trình Three.js Cơ Bản: Khám Phá Môi Trường Đồ Họa 3D WebGL

Three.js là thư viện JavaScript hàng đầu thế giới trong việc trừu tượng hóa sức mạnh của WebGL, mở ra cánh cửa kiến tạo không gian 3D tương tác thời gian thực ngay trên trình duyệt mà không đòi hỏi bất kỳ plugin hay phần mềm trung gian nào. Từ nguyên lý biến đổi đồ họa Rasterization tầng thấp, hệ tọa độ Cartesian đến kiến trúc cốt lõi gồm Scene, Camera, Renderer và vòng lặp hoạt họa GameLoop, bài phân tích chuyên sâu này sẽ giúp bạn làm chủ trọn vẹn nền tảng đồ họa 3D hiện đại trên nền tảng Web.

Không gian đồ họa 3D hình học kỹ thuật số dựng trên nền tảng WebGL và Three.js
Mô phỏng không gian hình học 3 chiều kết xuất bằng công nghệ WebGL trên trình duyệt.

1. Bản chất đồ họa số: Đối chiếu chuyên sâu Raster Graphics và Vector Graphics

Trước khi bắt tay vào viết mã nguồn 3D, bất kỳ kỹ sư phần mềm nào cũng cần hiểu thấu đáo bản chất của hai hệ đồ họa nền tảng chi phối toàn bộ giao diện máy tính: Hình ảnh Raster và Hình ảnh Vector. Mối quan hệ giữa hai định dạng này quyết định trực tiếp cách các bộ vi xử lý đồ họa (GPU) render từng khung hình lên màn hình.

Hình ảnh Raster (Raster Graphics): Được cấu thành từ một ma trận lưới gồm vô số điểm ảnh (pixels). Mỗi điểm ảnh lưu trữ một giá trị màu sắc cụ thể (RGB hoặc RGBA). Khi kích thước ảnh hiển thị tăng lên vượt quá độ phân giải gốc, hiện tượng “vỡ hạt” (pixelation) xuất hiện do máy tính buộc phải nội suy các pixel trống. Bù lại, Raster có khả năng tái tạo dải màu sắc phong phú, độ tương phản mượt mà và chi tiết tự nhiên của ảnh chụp thực tế.

Hình ảnh Vector (Vector Graphics): Không sử dụng các hạt điểm ảnh cố định, ảnh Vector được định nghĩa bằng các công thức toán học (tọa độ các điểm neo, đường cong Bezier, đa giác). Do đó, ảnh vector sở hữu đặc tính thu phóng vô tận (infinite scalability) mà không bao giờ mất nét, kích thước tệp thường siêu nhẹ nhưng không thể tái tạo chân thực các bề mặt chất liệu phức tạp như da người hay ánh sáng tự nhiên.

Thuộc tính Kỹ thuật Đồ Họa Raster (Bitmap / Pixels) Đồ Họa Vector (Mathematical Paths)
Cơ chế cấu thành Lưới ma trận 2D chứa các pixel màu tĩnh độc lập. Tập hợp các phương trình toán học xác định điểm, đường nối và diện tích.
Khả năng thu phóng Bị giới hạn bởi độ phân giải; zoom lớn sẽ bị mờ và vỡ điểm ảnh. Thu phóng vô hạn không suy giảm chất lượng hiển thị.
Dung lượng lưu trữ Tỉ lệ thuận với kích thước pixel và độ sâu màu (File size lớn). Chỉ lưu trữ tham số hàm số và tọa độ (File size cực nhỏ gọn).
Ứng dụng thực tế Ảnh chụp kỹ thuật số, kết cấu bề mặt 3D (Texture maps), video frame. Logo, icon, typography (SVG), font chữ hiển thị, bản vẽ CAD.

2. WebGL: Động cơ quang hóa điểm ảnh (Rasterization Engine) tầng thấp

Rất nhiều lập trình viên hiểu lầm WebGL là một “API 3D kỳ diệu”. Nhưng trên thực tế, WebGL (Web Graphics Library) là một Rasterization Engine tầng thấp dựa trên đặc tả kỹ thuật OpenGL ES. Nó chỉ có một nhiệm vụ duy nhất: chạy mã nguồn bạn viết để tính toán và biến đổi các đỉnh tọa độ thành các điểm (Points), đường thẳng (Lines) và tam giác (Triangles) lên bộ đệm khung hình (Framebuffer).

Tại sao nền tảng 3D lại chọn hình tam giác làm hạt nhân? Trong hình học không gian, 3 điểm không thẳng hàng luôn xác định duy nhất một mặt phẳng phẳng tuyệt đối. Khác với hình tứ giác hay đa giác nhiều cạnh (có nguy cơ bị cong vênh hoặc uốn khúc), hình tam giác luôn bảo đảm tính phẳng, giúp thuật toán đổ bóng (Shading) và tính toán pháp tuyến ánh sáng của GPU vận hành với tốc độ cực đại.

Nguyên lý làm việc của WebGL: Lập trình viên phải trực tiếp viết hai chương trình shader biên dịch bằng ngôn ngữ GLSL (OpenGL Shading Language): Vertex Shader (tính toán vị trí các đỉnh không gian) và Fragment Shader (tính toán màu sắc cho từng pixel trên bề mặt tam giác). Để vẽ một khối lập phương đơn giản bằng WebGL thuần túy, bạn có thể phải viết từ 100 đến 150 dòng mã cấu hình bộ đệm Vertex Buffer Objects (VBO) vô cùng nặng nhọc.

3. Vị thế của Three.js: Tầng trừu tượng hóa giải phóng sức sáng tạo

Đây chính là lý do Three.js ra đời. Được khởi xướng bởi Ricardo Cabello (Mr.doob), Three.js đóng vai trò như một lớp bọc cấp cao (High-level Abstraction Layer) đứng trên WebGL. Three.js chuyển đổi toàn bộ quy trình cấu hình bộ đệm, ma trận biến đổi đại số tuyến tính và mã nguồn GLSL phức tạp thành các đối tượng hướng đối tượng (OOP) trực quan trong JavaScript.

Nhờ Three.js, bạn có thể khởi tạo một thế giới 3D hoàn chỉnh chỉ với vài chục dòng code quen thuộc, tự động tận dụng tối đa sức mạnh tăng tốc phần cứng của GPU mà không cần đào sâu vào chi tiết vi mô của OpenGL ES.

// KIẾN TRÚC NGĂN XẾP ĐỒ HỌA 3D TRÊN WEB (WEB 3D TECH STACK)
[Mã ứng dụng của bạn (Three.js API)]
    │ (Trừu tượng hóa đối tượng: Scene, Mesh, Camera, Light)
▼
[Thư viện Three.js Core Engine]
    │ (Sinh tự động ma trận World Matrix, GLSL Shaders & VBOs)
▼
[Trình duyệt: WebGL API (OpenGL ES 2.0 / 3.0)]
    │ (Giao tiếp trực tiếp với Driver phần cứng đồ họa)
▼
[Bộ vi xử lý đồ họa GPU (NVIDIA / AMD / Apple Silicon / Intel)]
    │ (Quang hóa song song hàng triệu điểm ảnh)
▼
[Bề mặt hiển thị: Phần tử HTML5 <canvas> trên màn hình]

4. Hệ sinh thái cốt lõi: Bộ tứ nguyên tử kiến tạo không gian 3D

Mọi ứng dụng 3D thời gian thực được xây dựng bằng Three.js đều vận hành xoay quanh 4 thành phần thiết yếu, tương tự như một phim trường điện ảnh thu nhỏ:

  1. Không gian bối cảnh (Scene): Đóng vai trò như một “vũ trụ thu nhỏ” (Graph Scene Tree). Scene là nơi lưu giữ toàn bộ các thực thể 3D, ánh sáng (Lights), sương mù (Fog), và các mô hình hình học. Bất kỳ đối tượng nào muốn xuất hiện trước mắt người dùng đều phải được đưa vào Scene thông qua phương thức scene.add(object).
  2. Ống kính quan sát (Camera): Định nghĩa góc nhìn, tiêu cự và phạm vi không gian mà người xem có thể nhìn thấy. Camera đóng vai trò quyết định khung hình nào trong Scene sẽ được thu nhận để đưa vào bộ xử lý.
  3. Bề mặt kết xuất (HTML5 Canvas): Là một thẻ phần tử DOM chuẩn của HTML5 (<canvas>). Canvas đóng vai trò như một bức màn chiếu rạp phim hoặc màn hình điện thoại – nơi các pixel màu sắc do GPU tính toán được in trực tiếp lên giao diện trình duyệt.
  4. Cỗ máy kết xuất (WebGLRenderer): Bộ phận “máy móc” đóng vai trò chỉ huy. Renderer nhận đầu vào gồm một Scene cụ thể và một Camera nhất định, sau đó tiến hành toàn bộ các phép chiếu hình học để vẽ hình ảnh tương ứng lên bề mặt Canvas.

Khái niệm then chốt: Đối tượng Mesh là gì?

Bản thân Scene, Camera hay Renderer đều là những thành phần điều khiển vô hình. Thứ trực tiếp hiển thị hình thù trên màn hình chính là Mesh (Lưới đa giác). Một đối tượng Mesh được ghép nối từ hai thành tố cơ bản:

Geometry (Hình học)
Định nghĩa khung xương không gian, tập hợp các tọa độ đỉnh (Vertices) và các mặt tam giác cấu thành hình dáng vật thể.
Material (Vật liệu / Bề mặt)
Quy định đặc tính quang học của bề mặt: màu sắc, độ phản xạ kim loại, độ nhám (Roughness), độ trong suốt hoặc chế độ hiển thị khung dây (Wireframe).

5. Giải mã PerspectiveCamera: 4 tham số quang học hình nón cụt (Frustum)

Trong Three.js có hai loại Camera chính: PerspectiveCamera (Camera phối cảnh xa gần như mắt người) và OrthographicCamera (Camera đẳng cự song song thường dùng trong game 2.5D hoặc bản vẽ kỹ thuật CAD). Để tạo cảm giác không gian chân thực nhất, PerspectiveCamera là lựa chọn tiêu chuẩn hàng đầu.

Cú pháp khởi tạo PerspectiveCamera yêu cầu 4 tham số quang học bắt buộc:

// Cú pháp khởi tạo Camera phối cảnh trong Three.js:
const camera = new THREE.PerspectiveCamera(
  75,                              // 1. fov (Field of View): Góc mở quan sát (đơn vị: độ)
  window.innerWidth / window.innerHeight, // 2. aspect (Tỉ lệ khung hình chiều rộng / chiều cao)
  0.1,                             // 3. near (Mặt phẳng cắt cực gần)
  1000                            // 4. far (Mặt phẳng cắt cực xa)
);

Ý nghĩa vật lý chuyên sâu của từng tham số:

  • fov (Field of View – Trường nhìn dọc): Góc mở quan sát của ống kính theo phương thẳng đứng tính bằng độ (từ 1 đến 179 độ). Giá trị thông dụng dao động từ 45 đến 75 độ. Góc nhìn càng lớn, trường nhìn càng rộng (hiệu ứng góc rộng / fisheye), khiến các vật thể ở xa trông nhỏ đi nhanh chóng.
  • aspect (Tỉ lệ khung hình): Tỉ lệ giữa chiều rộng và chiều cao của vùng nhìn. Trong các ứng dụng toàn màn hình, tỉ lệ này thường được gán bằng window.innerWidth / window.innerHeight để hình ảnh không bị méo mó tỉ lệ (méo hình tròn thành hình elip).
  • near & far (Mặt phẳng cắt không gian – Clipping Planes): Khoảng cách tính từ vị trí Camera đến điểm gần nhất và xa nhất mà camera có thể ghi hình. Bất kỳ vật thể nào nằm ngoài khoảng cách này (gần hơn near hoặc xa hơn far) sẽ bị GPU loại bỏ hoàn toàn (Clipping). Điều kiện bắt buộc là far > near > 0.

6. Hướng dẫn thực hành: Khởi tạo khối cầu 3D đầu tiên (Hands-on Code)

Dưới đây là toàn bộ mã nguồn hoàn chỉnh để dựng một đối tượng khối cầu 3D dạng khung dây (Wireframe Sphere) tự quay trong không gian ba chiều bằng Three.js:

// === BƯỚC 1: KHỞI TẠO BỘ TỨ CỐT LÕI ===

const scene = new THREE.Scene();
scene.background = new THREE.Color(‘#0f172a’); // Đặt màu nền không gian

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 3; // Lùi camera về phía sau trục Z để quan sát vật thể tại gốc tọa độ (0,0,0)

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement); // Nhúng thẻ <canvas> vào cấu trúc DOM HTML

// === BƯỚC 2: TẠO VẬT THỂ (GEOMETRY + MATERIAL = MESH) ===

// Bán kính r=1, 16 phân đoạn kinh tuyến, 12 phân đoạn vĩ tuyến
const geometry = new THREE.SphereGeometry(1, 16, 12);
const material = new THREE.MeshBasicMaterial({
  color: 0x38bdf8,
  wireframe: true // Hiển thị khung dây đa giác
});
const sphere = new THREE.Mesh(geometry, material);
scene.add(sphere); // Nạp vật thể vào vũ trụ 3D

// === BƯỚC 3: VÒNG LẶP HOẠT HỌA THỜI GIAN THỰC (ANIMATION LOOP) ===

function animate() {
  requestAnimationFrame(animate);
  // Cập nhật ma trận góc xoay (Euler Rotation)
  sphere.rotation.x += 0.01;
  sphere.rotation.y += 0.008;
  // Vẽ lại khung hình mới
  renderer.render(scene, camera);
}
animate();

7. Phân tích vòng lặp Game Loop và kỹ thuật requestAnimationFrame

Một câu hỏi kỹ thuật kinh điển: Tại sao trong lập trình đồ họa 3D, chúng ta không dùng setInterval() hay setTimeout() mà bắt buộc phải dùng requestAnimationFrame()?

Hàm requestAnimationFrame mang lại 3 ưu thế vượt trội mang tính quyết định đối với trải nghiệm người dùng:

  • Đồng bộ hóa tần số quét màn hình (Refresh Rate Synchronization): Trình duyệt sẽ tự động căn chỉnh thời điểm gọi hàm vẽ trùng khớp với chu kỳ quét của màn hình (thường là 60Hz, 120Hz hoặc 144Hz), triệt tiêu hoàn toàn hiện tượng giật cục hay xé hình (Screen Tearing).
  • Tiết kiệm năng lượng và tài nguyên GPU: Khi người dùng chuyển sang tab khác hoặc thu nhỏ trình duyệt, requestAnimationFrame sẽ tạm dừng hoạt động. Điều này giúp CPU và card đồ họa không bị ép chạy hết công suất vô ích, tiết kiệm pin tối đa cho thiết bị di động.
  • Phân tách logic hoạt họa: Kiến trúc GameLoop chuẩn luôn chia làm 2 giai đoạn tách bạch trong từng frame: Hàm update() (tính toán vị trí, gia tốc, góc xoay) và Hàm render() (thực thi việc vẽ của GPU).

8. Xử lý bài toán Window Resizing chuẩn Production

Khi mở một ứng dụng Three.js lên trình duyệt, nếu người dùng co giãn kích thước cửa sổ hoặc xoay ngang màn hình điện thoại, thẻ <canvas> sẽ không thể tự động thay đổi tỉ lệ nếu bạn không lắng nghe sự kiện resize. Kết quả là hình khối 3D sẽ bị kéo giãn méo mó hoặc xuất hiện các dải màu trắng thừa thãi.

Đoạn mã chuẩn hóa sự kiện co giãn màn hình trong môi trường sản xuất thực tế:

// Đăng ký bộ lắng nghe sự kiện thay đổi kích thước cửa sổ chuẩn mực:
window.addEventListener(‘resize’, () => {
  // 1. Cập nhật lại tỉ lệ khung hình mới của camera
  camera.aspect = window.innerWidth / window.innerHeight;
  // 2. Kích hoạt tính toán lại ma trận chiếu phối cảnh (Cực kỳ quan trọng!)
  camera.updateProjectionMatrix();
  // 3. Cập nhật lại kích thước bề mặt kết xuất của Renderer
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 4. Đồng bộ hóa tỉ lệ mật độ điểm ảnh (Retina / High-DPI screens)
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});

9. Khảo sát công cụ & So sánh giá thiết bị hỗ trợ lập trình đồ họa 3D

Đối với các lập trình viên Frontend và kỹ sư đồ họa đang tìm kiếm phần cứng máy trạm hoặc tài liệu chuyên ngành để tăng tốc quy trình phát triển WebGL / Three.js, quý độc giả có thể tham khảo so sánh giá tại các liên kết dưới đây:

Sách giáo trình chuyên sâu Three.js & WebGL Lập Trình Game Web 3D
Tài liệu hướng dẫn từ cơ bản đến nâng cao về Shader GLSL, Vật lý 3D và Tối ưu hiệu năng WebGL


So sánh giá trên Shopee

Card màn hình đồ họa GPU rời hỗ trợ WebGL 2.0 & DirectX Raytracing
Phần cứng xử lý đồ họa tăng tốc dựng hình thời gian thực cho nhà phát triển Web 3D


So sánh giá trên Shopee

Màn hình đồ họa IPS chuẩn màu 144Hz cho kỹ sư lập trình đồ họa và UI 3D
Tần số quét cao giúp kiểm thử mượt mà các hoạt họa 60fps – 120fps trong Three.js GameLoop


So sánh giá trên Shopee

Nguồn dữ liệu tham chiếu và đối chiếu (Plain Text Citations):

– https://viblo.asia/p/threejs-bai-1-lam-quen-voi-moi-truong-3d-cua-threejs-vyDZO7ROZwj

– https://threejs.org/docs/#api/en/core/Geometry

– https://threejs.org/examples/#webgl_loader_mmd

– https://www.khronos.org/webgl/

– https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API

Back to top button