three.js cho người làm web · Phần 2
Cập nhật tháng 10/2026. Mã mẫu viết cho three.js 0.186.1 (r186), bản mới nhất trên npm lúc viết bài. Tên hàm có thể đổi giữa các bản, hãy đối chiếu tài liệu chính thức trước khi dùng.
Bài này dành cho ai: người làm web đã dựng được cảnh three.js đầu tiên và nay phải đưa mô hình 3D thật (sofa, bao bì, máy móc) lên trang sản phẩm.
Bạn sẽ nắm được gì: cách tải glTF/GLB, nén mô hình và ảnh vân, chiếu sáng bằng môi trường, đếm draw call, tải trễ, giải phóng bộ nhớ, kèm checklist trước khi bàn giao.
Thời gian đọc: khoảng 9 phút.
Ở bài three.js cho người làm web: dựng cảnh 3D đầu tiên, khối hộp chỉ nặng vài byte. Mô hình thật xuất thẳng từ Blender có thể nặng hàng chục MB, điện thoại tầm trung tải lâu và nóng máy. Kinh nghiệm của chúng tôi: phần lớn vấn đề hiệu năng nằm ở file mô hình, không ở mã.

1. Chọn glTF/GLB và tải bằng GLTFLoader
Manual three.js khuyên dùng glTF cho hầu hết trường hợp vì định dạng này sinh ra để giao mô hình cho ứng dụng thời gian thực: gọn khi truyền, nhanh khi nạp. Bản .glb gói tất cả vào một tệp nhị phân, tiện đặt lên WordPress hay CDN.
GLTFLoader là addon, phải import riêng. Nếu dùng import map như bài trước, thêm dòng "three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/" cạnh dòng three. Mô hình đen thui hoặc không thấy đâu? Manual gợi ý thêm đèn, thử phóng to/thu nhỏ 1000 lần và xem tab Network có ảnh vân trỏ sai đường dẫn không.
2. Nén trước khi tải: Draco, meshopt và KTX2
Có hai thứ cần nén: hình học (đỉnh, mặt) và ảnh vân. Công cụ dòng lệnh glTF Transform làm cả hai trong một lệnh:
gltf-transform inspect sofa.glb
gltf-transform optimize sofa.glb sofa-web.glb –compress meshopt –texture-compress webp –texture-size 1024
inspect liệt kê lưới, vật liệu, dung lượng ảnh vân. optimize mặc định còn gộp lưới để giảm draw call (--join), dùng instancing và giới hạn ảnh vân ở 2048px; trang bán hàng thường chỉ cần 1024px.
Draco
Nén hình học mạnh, hợp mô hình tĩnh nhiều đỉnh; cần tải thêm bộ giải mã WebAssembly.
Meshopt
Nén cả hình học lẫn chuyển động, giải mã nhanh. Là lựa chọn mặc định của lệnh optimize.
KTX2 (Basis)
Ảnh vân giữ dạng nén trong bộ nhớ card đồ hoạ; WebP, AVIF chỉ nhẹ lúc tải.
Muốn xuất KTX2 (--texture-compress ktx2), máy bạn cần cài thêm KTX-Software của Khronos. Phía trình duyệt, GLTFLoader cần được gắn bộ giải mã tương ứng:
import { DRACOLoader } from ‘three/addons/loaders/DRACOLoader.js’;
import { KTX2Loader } from ‘three/addons/loaders/KTX2Loader.js’;
import { MeshoptDecoder } from ‘three/addons/libs/meshopt_decoder.module.js’;
const libs = ‘https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/libs/’;
const loader = new GLTFLoader()
.setDRACOLoader(new DRACOLoader().setDecoderPath(libs + ‘draco/gltf/’))
.setKTX2Loader(new KTX2Loader().setTranscoderPath(libs + ‘basis/’).detectSupport(renderer))
.setMeshoptDecoder(MeshoptDecoder);
const gltf = await loader.loadAsync(‘/models/sofa-web.glb’);
scene.add(gltf.scene);

3. Ánh sáng môi trường: RoomEnvironment hoặc ảnh HDR
Vật liệu PBR như MeshStandardMaterial trông “nhựa” nếu chỉ có đèn định hướng. Cách rẻ nhất để phản chiếu tự nhiên là gán scene.environment. RoomEnvironment dựng sẵn một căn phòng ảo, không phải tải file nào:
const pmrem = new THREE.PMREMGenerator(renderer);
const room = new RoomEnvironment();
scene.environment = pmrem.fromScene(room).texture;
room.dispose();
pmrem.dispose();
Cần ánh sáng thật của một không gian, dùng ảnh .hdr với HDRLoader (từ r180, RGBELoader cũ đã bị đánh dấu ngừng dùng) và đặt mapping = THREE.EquirectangularReflectionMapping.
4. Hiệu năng trên điện thoại: đếm trước, sửa sau
Bài trước đã dừng vòng lặp khi canvas khuất; bước tiếp theo là nhìn số liệu thay vì đoán. renderer.info.render.calls cho biết số lệnh vẽ trong khung hình vừa rồi, renderer.info.memory cho biết số hình học, ảnh vân đang nằm trong bộ nhớ.
- Draw call: mỗi lưới với một vật liệu thường tốn ít nhất một lệnh vẽ. 300 con ốc tách rời là 300 lệnh. Gộp lưới tĩnh bằng
--joinhoặcmergeGeometriestrongBufferGeometryUtils; vật thể lặp lại (ghế trong hội trường) dùngInstancedMesh. - Tỉ lệ điểm ảnh: trên điện thoại, thử hạ từ 2 xuống 1,5 rồi so bằng mắt.
- Bóng đổ: thay bóng thời gian thực bằng ảnh bóng mờ dưới chân mô hình.

5. Tải trễ: đừng bắt khách tải 3D khi chưa cần
Nếu nạp thư viện và mô hình ngay khi mở trang, chúng tranh băng thông với ảnh chính và kéo chậm LCP (xem lại Core Web Vitals cho chủ doanh nghiệp). Cách làm: hiển thị ảnh tĩnh của sản phẩm trước, chỉ import() mã 3D khi khung sắp cuộn tới hoặc khi khách bấm “Xem 3D”:
const watcher = new IntersectionObserver(async ([entry]) => {
if (!entry.isIntersecting) return;
watcher.disconnect();
const { startViewer } = await import(‘/js/xem-3d.js’);
startViewer(holder);
}, { rootMargin: ‘300px’ });
watcher.observe(holder);
Ảnh tĩnh cùng kích thước khung 3D để trang không xô lệch (CLS).
6. Giải phóng bộ nhớ khi đổi hoặc gỡ mô hình
Theo manual “How to dispose of objects”, three.js không tự giải phóng tài nguyên card đồ hoạ; gỡ lưới khỏi cảnh không xoá hình học và vật liệu. Khi đổi mô hình hoặc trang SPA chuyển đi, hãy dọn:
root.traverse((obj) => {
if (!obj.isMesh) return;
obj.geometry.dispose();
for (const material of [].concat(obj.material)) {
for (const value of Object.values(material)) {
if (value && value.isTexture) value.dispose();
}
material.dispose();
}
});
root.removeFromParent();
}
Kiểm tra lại bằng renderer.info.memory: đổi mô hình vài lần mà số ảnh vân cứ tăng là đang rò rỉ. Vật liệu, ảnh vân dùng chung thì chỉ dispose khi không còn mô hình nào dùng.
Ví dụ minh hoạ: một xưởng gỗ ở Bình Dương đưa 12 mẫu bàn ghế lên trang sản phẩm. Mỗi file gốc khoảng 25 MB. Sau khi chạy optimize với meshopt và ảnh vân 1024px, giả sử mỗi file còn vài MB; trang hiển thị ảnh tĩnh trước, khách bấm mới tải 3D, đổi mẫu thì dọn mẫu cũ. Hãy đo bằng inspect trước và sau. Muốn khách đặt luôn mẫu vào phòng mình, xem thêm AR thử nội thất trên web.
7. Checklist trước khi bàn giao trang có 3D
- Mô hình là
.glb, đã chạyinspectvàoptimize, ghi lại dung lượng trước/sau. - Ảnh vân không quá 1024–2048px; cân nhắc KTX2 nếu mô hình nhiều ảnh vân.
- Chỉ gắn bộ giải mã file thật sự cần; ghim phiên bản three.js; có
scene.environment, ít đèn và bóng đổ. - Draw call mỗi khung đã đo bằng
renderer.info, lưới tĩnh đã gộp. - Ảnh tĩnh hiển thị trước, mã 3D tải trễ, khung giữ đúng kích thước.
- Vòng lặp dừng khi canvas khuất; tôn trọng
prefers-reduced-motion. - Đổi mô hình có hàm dispose,
renderer.info.memorykhông tăng mãi. - Thử trên điện thoại tầm trung thật, mạng 4G.
8. Thuật ngữ cần biết
- glTF/GLB: định dạng mở của Khronos để truyền mô hình 3D; GLB là bản một tệp nhị phân. Nguồn: Khronos glTF.
- Draw call: một lệnh CPU gửi card đồ hoạ để vẽ một nhóm hình; quá nhiều lệnh làm khung hình chậm. Nguồn: three.js manual: Optimizing Lots of Objects.
- KTX2: định dạng ảnh vân của Khronos, dùng nén Basis để giữ dạng nén trong bộ nhớ card đồ hoạ. Nguồn: Khronos KTX.
- PMREM: bản đồ môi trường được lọc sẵn theo độ nhám để vật liệu PBR phản chiếu đúng. Nguồn: three.js PMREMGenerator.
9. Tìm hiểu thêm
- three.js manual: Loading 3D Models và tài liệu GLTFLoader.
- How to dispose of Objects: những gì phải tự giải phóng.
- glTF Transform CLI, meshoptimizer và Draco.
10. Câu hỏi thường gặp
Nên chọn Draco hay meshopt?
Meshopt giải mã nhanh, nén được cả chuyển động; Draco thường cho file nhỏ hơn với mô hình tĩnh nhiều đỉnh. Xuất cả hai, so dung lượng và thời gian hiển thị trên điện thoại thật rồi chọn.
Mô hình bao nhiêu MB là ổn cho trang sản phẩm?
Không có ngưỡng chính thức. Nguyên tắc của chúng tôi: càng nhỏ càng tốt, tải sau nội dung chính và đo trên mạng 4G; chờ vài giây vẫn chưa thấy mô hình thì giảm ảnh vân hoặc đơn giản hoá lưới (--simplify).
Đọc tiếp
- Bài trước (Lập trình & Thiết kế): Người làm web tự học công nghệ mới mỗi quý mà không bị ngợp: một chủ đề, một dự án, 30 phút mỗi ngày
- Bài sau trong chuyên mục Lập trình & Thiết kế: Thiết kế trang dịch vụ chuyển đổi tốt cho doanh nghiệp nhỏ: một mục tiêu, bằng chứng thật, CTA nhất quán
- Nên đọc cùng: three.js cho người làm web: dựng cảnh 3D đầu tiên và biết khi nào nên dùng
PDL Digital đào tạo đội ngũ làm web của doanh nghiệp từ nền tảng JavaScript đến 3D trên web và ứng dụng AI vào quy trình lập trình. Xem trang đào tạo để chọn khoá phù hợp.



