Tạo cảnh 3D đầu tiên với Three.js

Giới thiệu Các trình duyệt hiện đại hỗ trợ WebGL. Với WebGL, bạn có thể trực tiếp sử dụng các tài nguyên xử lý của card đồ họa (GPU) và tạo các cảnh 3D với hiệu năng cao. Tuy nhiên, lập trình WebGL rất phức tạp, cần viết nhiều code, dễ gặp lỗi. Three.js là

Giới thiệu

Các trình duyệt hiện đại hỗ trợ WebGL. Với WebGL, bạn có thể trực tiếp sử dụng các tài nguyên xử lý của card đồ họa (GPU) và tạo các cảnh 3D với hiệu năng cao. Tuy nhiên, lập trình WebGL rất phức tạp, cần viết nhiều code, dễ gặp lỗi. Three.js là một thư viện JS để tạo và hiển thị đồ họa 3D trên trình duyệt sử dụng WebGL. Three.js giúp việc lập trình 3D trên trình duyệt dễ dàng hơn.

Bạn có thể tìm hiểu lịch sử phát triển của thư viện ở Wikipedia:

Three.js – Wikipedia

Trang chủ của thư viện:

Three.js – JavaScript 3D Library

Manual chính thức từ trang chủ:

Three.js Manual

Bạn có thể học theo sách “Learn Three.js”. Sách này mô tả đầy đủ các mục, có nhiều ví dụ:

Learn Three.js – Third Edition | Packt

Bạn có thể xem ví dụ của sách trên online ở đây:

All (150+) learning Three.js third edition examples online – SmartJava

Bạn cũng có thể học theo tutorial sau:

Discover Three.js

Các bài viết trên Viblo:

Three.js – Viblo

Các yêu cầu để sử dụng Three.js

Để chạy một trang web sử dụng Three.js, trình duyệt của bạn phải hỗ trợ WebGL. Ngoài ra, để chạy các ví dụ mà tôi sẽ viết thì trình duyệt của bạn cũng cần hỗ trợ load script dạng module, hỗ trợ lập trình hướng đối tượng trong JS. Có lẽ bạn sẽ không cần quá quan tâm vì hầu hết các trình duyệt hiện nay đều đã hỗ trợ tất cả những điều đó rồi.

Các source code đi kèm được tôi đẩy lên GitHub để bạn có thể lấy về:

https://github.com/lockex1987/learn-threejs

Các source code đều là các file định dạng text (html, js, css). Để chỉnh sửa, bạn chỉ cần bất cứ text editor nào mà bạn muốn (ví dụ VSCode).

Để chạy các file ví dụ mà tôi viết ở máy của bạn, bạn cần có web server vì một số ví dụ có tải các tài nguyên ngoài cho Texture và model. Ngoài ra các ví dụ viết kiểu JS module nên chắc chắn cần web server. Bạn không thể chạy file html dạng file:/// được.

Bạn có thể tạo một web server đơn giản bằng PHP như sau:

php -S localhost:8000

Tải thư viện Three.js

Bạn có thể download file zip release từ GitHub ở địa chỉ sau:

Releases · mrdoob/three.js

File download khá là nặng, tầm hơn 300MB do chứa cả documentation, editor, code HTML của các ví dụ,… Do đó bạn không nên làm cách này. Bạn chỉ cần một file thư viện Three.js core ở thư mục build và tùy trường hợp cụ thể sẽ cần thêm một số file bổ sung ở thư mục examples.

Cấu trúc thư mục cùng các file mà bạn cần là:

build
    three.cjs
    three.js
    three.min.js
    three.module.js
examples
    fonts
    js
        controls
            OrbitControls.js
        loaders
        ...
    jsm
        controls
            OrbitControls.js
        loaders
src

Bạn có thể sử dụng CDN ở địa chỉ sau:

https://unpkg.com/browse/three/

Ví dụ địa chỉ của thư viện Three.js core là:

https://unpkg.com/[email protected]/build/three.module.js

Địa chỉ của thư viện bổ sung nếu cần sử dụng OrbitControls là:

https://unpkg.com/[email protected]/examples/jsm/controls/OrbitControls.js

Các ví dụ tôi viết sẽ sử dụng CDN. Phiên bản sử dụng là r137 (release ngày 28/1/2022). Chú ý bạn cần đồng bộ phiên bản của thư viện Three.js core ở thư mục build với phiên bản của các thư viện bổ sung trong thư mục examples.

Bạn có thể sử dụng npm:

npm install three

Lệnh npm trên thực hiện khá là nhanh do chỉ download các thư mục build, examples, src.

Nếu bạn có nhu cầu cần nâng cấp giữa các phiên bản thì có thể làm theo hướng dẫn ở địa chỉ sau:

Migration Guide · mrdoob/three.js Wiki · GitHub

Tạo khung HTML, CSS, JS cho các ví dụ

Mỗi ví dụ tôi viết thường bao gồm ba file: một file HTML, một file CSS, một file JS.

Chúng ta hãy tạo một file khung HTML (chapter-01/01-basic-skeleton.html):

<!DOCTYPEhtml><html><head><metacharset="UTF-8"/><title>Example 01.01 - Basic skeleton</title><linkrel="icon"href="../images/logo.svg"/><linkrel="stylesheet"href="../css/style.css"/></head><body><canvasid="webglOutput"></canvas><scriptsrc="js/01-01.js"type="module"></script></body></html>

Trang web chỉ chứa một thẻ <canvas> là nơi mà để vẽ các cảnh 3D.

Chú ý chúng ta load file JS theo kiểu module (thẻ <script> có thuộc tính type là module).

Khung file CSS (css/style.css):

body{margin: 0;overflow: hidden;}html,
body{height: 100%;}#webglOutput{width: 100%;height: 100%;}

Các style đảm bảo cảnh 3D của chúng ta sẽ chiếm toàn màn hình và không bị scroll.

Khung file JS (chapter-01/js/01-01.js):

import{
    Scene,
    PerspectiveCamera,
    WebGLRenderer,
    BoxGeometry,
    MeshNormalMaterial,
    Mesh,REVISION}from'https://unpkg.com/[email protected]/build/three.module.js';classThreejsExample{constructor(){alert('Phiên bản Three.js là: '+REVISION);}}newThreejsExample();

Ở đầu file JS, chúng ta sẽ import các class của Three.js cần sử dụng. Tiếp theo chúng ta khai báo class ThreejsExample. Các nghiệp vụ của chương trình sẽ ở trong class này. Cuối cùng chúng ta sẽ khởi tạo một đối tượng ThreejsExample để thực thi các nghiệp vụ.

Các ví dụ có phần HTML và CSS gần như giống nhau hết, chỉ có phần JS là khác nhau.

Ví dụ 01.01 – Khung cơ bản

Ví dụ trên chỉ hiển thị một trang web trắng cùng thông báo “Phiên bản Three.js là: 137“.

Render một đối tượng 3D cơ bản

Chúng ta hãy cùng render một hình lập phương 3D với ít code nhất gồm 6 bước.

Bước 1: Tạo một Scene để chứa các đối tượng 3D (Mesh), các nguồn sáng (Light).

createScene(){const scene =newScene();return scene;}constructor(canvas){this.scene =this.createScene();}

Bước 2: Tạo một Camera để chỉ định vị trí nhìn, hướng nhìn. Chúng ta sẽ tìm hiểu thêm về các tham số khi khởi tạo Camera ở các bài sau.

createCamera(){const aspect = window.innerWidth / window.innerHeight;const camera =newPerspectiveCamera(45, aspect,0.1,1000);
    camera.position.set(-30,40,30);
    camera.lookAt(this.scene.position);return camera;}constructor(canvas){this.camera =this.createCamera();}

Bước 3: Tạo một Renderer để render. Chúng ta thường dùng WebGLRenderer. Ngoài ra còn có Renderer dựa vào CSS, SVG nhưng ít được sử dụng. Chúng ta sẽ truyền đối tượng thẻ canvas cho Renderer. Sau này, đối tượng canvas có thể lấy lại bằng thuộc tính this.renderer.domElement.

Chúng ta thiết lập màu nền của là màu đen (new Color(0x000000)) bằng phương thức setClearColor. Chúng ta cũng thiết lập độ lớn của cảnh bằng phương thức setSize. Bằng cách truyền window.innerWidthwindow.innerHeight, chúng ta sẽ sử dụng toàn bộ không gian của màn hình.

createRenderer(canvas){const renderer =newWebGLRenderer({
        canvas,
        antialias:true});
    renderer.setClearColor(newColor(0x000000));
    renderer.setSize(window.innerWidth, window.innerHeight);return renderer;}constructor(canvas){this.renderer =this.createRenderer(canvas);}

Bước 4: Tạo một đối tượng Mesh hình lập phương và thêm nó vào Scene. Mesh được tạo lên từ Geometry và Material. Chúng ta sẽ dùng MeshNormalMaterial hoặc MeshBasicMaterial để chưa cần tới Light mà vẫn nhìn thấy đối tượng. Chúng ta cũng thiết lập vị trí của đối tượng.

createCube(){const cubeGeometry =newBoxGeometry(16,16,16);const cubeMaterial =newMeshNormalMaterial();const cube =newMesh(cubeGeometry, cubeMaterial);
    cube.position.set(-4,3,0);return cube;}constructor(canvas){const cube =this.createCube();this.scene.add(cube);}

Bước 5: Chúng ta yêu cầu Renderer hãy render Scene với Camera đi.

render(){this.renderer.render(this.scene,this.camera);}constructor(canvas){this.render();}

Bước 6: Khởi tạo đối tượng ThreejsExample để chạy những nghiệp vụ trên.

newThreejsExample(document.querySelector('#webglOutput'));

Toàn bộ code đầy đủ là (chapter-01/js/01-02.js):

import{
    Scene,
    PerspectiveCamera,
    WebGLRenderer,
    Color,
    BoxGeometry,
    MeshNormalMaterial,
    Mesh
}from'https://unpkg.com/[email protected]/build/three.module.js';classThreejsExample{constructor(canvas){this.scene =this.createScene();this.camera =this.createCamera();this.renderer =this.createRenderer(canvas);const cube =this.createCube();this.scene.add(cube);this.render();}createScene(){const scene =newScene();return scene;}createCamera(){const aspect = window.innerWidth / window.innerHeight;const camera =newPerspectiveCamera(45, aspect,0.1,1000);
        camera.position.set(-30,40,30);
        camera.lookAt(this.scene.position);return camera;}createRenderer(canvas){const renderer =newWebGLRenderer({
            canvas,
            antialias:true});
        renderer.setClearColor(newColor(0x000000));
        renderer.setSize(window.innerWidth, window.innerHeight);return renderer;}createCube(){const cubeGeometry =newBoxGeometry(16,16,16);const cubeMaterial =newMeshNormalMaterial();const cube =newMesh(cubeGeometry, cubeMaterial);
        cube.position.set(-4,3,0);return cube;}render(){this.renderer.render(this.scene,this.camera);}}newThreejsExample(document.querySelector('#webglOutput'));

Ví dụ 01.02 – Scene đầu tiên

Nếu bạn mở ví dụ trên trình duyệt, chúng ta sẽ thấy một hình lập phương như sau:

01-02

Ví dụ đơn giản của chúng ta chỉ sử dụng các đối tượng cơ bản sau:

  • Scene
  • Camera (PerspectiveCamera)
  • Renderer (WebGLRenderer)
  • Geometry (BoxGeometry)
  • Material (MeshNormalMaterial)
  • Mesh

Các cảnh 3D đều được tạo từ các đối tượng cơ bản trên, cùng với đối tượng cơ bản khác là Light mà chúng ta chưa nhắc đến.

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ