Light (Ánh sáng) trong Three.js

Tạo bởi Hoàng Vũ, chỉnh sửa cuối lúc 12 tháng 1, 2025

Ánh sáng đóng vai trò quan trọng trong việc tạo ra hình ảnh chân thực trong không gian 3D. Three.js cung cấp nhiều loại ánh sáng khác nhau để đáp ứng nhu cầu đa dạng. Trong bài này, chúng ta sẽ tìm hiểu các loại ánh sáng phổ biến, cách sử dụng chúng và cách tạo bóng đổ (shadows) để tăng tính chân thực cho các đối tượng.

1. Các loại ánh sáng trong Three.js

1.1 AmbientLight (Ánh sáng môi trường)

AmbientLight chiếu sáng toàn bộ không gian một cách đồng đều, không tạo bóng hoặc hướng ánh sáng cụ thể. Đây là loại ánh sáng cơ bản để chiếu sáng toàn bộ cảnh.

Cách sử dụng:

const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); // Màu trắng, cường độ 0.5
scene.add(ambientLight);

1.2 DirectionalLight (Ánh sáng định hướng)

DirectionalLight phát ánh sáng theo một hướng cụ thể, giống như ánh sáng mặt trời. Ánh sáng từ DirectionalLight là song song và có thể tạo bóng đổ.

Cách sử dụng:

const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 10, 5); // Đặt vị trí nguồn sáng
scene.add(directionalLight);

Thêm bóng đổ:

directionalLight.castShadow = true;

1.3 PointLight (Ánh sáng điểm)

PointLight phát sáng từ một điểm cụ thể ra mọi hướng, giống như bóng đèn.

Cách sử dụng:

const pointLight = new THREE.PointLight(0xffffff, 1, 50); // Cường độ 1, phạm vi 50
pointLight.position.set(10, 10, 10);
scene.add(pointLight);

1.4 SpotLight (Ánh sáng điểm hội tụ)

SpotLight phát ánh sáng theo một hình nón, giống như đèn sân khấu. Loại ánh sáng này cũng có khả năng tạo bóng.

Cách sử dụng:

const spotLight = new THREE.SpotLight(0xffffff, 1);
spotLight.position.set(5, 10, 5);
scene.add(spotLight);

Thêm bóng đổ:

spotLight.castShadow = true;

1.5 HemisphereLight (Ánh sáng bán cầu)

HemisphereLight mô phỏng ánh sáng từ bầu trời (sky light) và mặt đất (ground light). Loại ánh sáng này không tạo bóng.

Cách sử dụng:

const hemisphereLight = new THREE.HemisphereLight(0x87CEEB, 0xFFFFFF, 0.5); 
// Màu bầu trời (Sky), màu mặt đất (Ground), cường độ 0.5
scene.add(hemisphereLight);

2. Cách sử dụng bóng đổ (Shadows)

Bóng đổ giúp các đối tượng trong cảnh trông chân thực hơn bằng cách phản ánh cách ánh sáng bị chắn bởi các vật thể. Three.js hỗ trợ bóng đổ nhưng cần được kích hoạt thủ công.

Bước 1: Bật bóng đổ cho renderer

Khi tạo renderer, bật thuộc tính shadowMap:

const renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;

Bước 2: Bật bóng đổ cho ánh sáng

Không phải ánh sáng nào cũng hỗ trợ bóng đổ. Chỉ DirectionalLight và SpotLight hỗ trợ tính năng này:

directionalLight.castShadow = true;
spotLight.castShadow = true;

Bước 3: Bật bóng đổ cho vật thể

Các vật thể muốn tạo hoặc nhận bóng đổ cần bật thuộc tính castShadow và receiveShadow:

const cube = new THREE.Mesh(
	  new THREE.BoxGeometry(),
	  new THREE.MeshStandardMaterial({ color: 0x00ff00 })
);
cube.castShadow = true; // Vật thể tạo bóng
cube.receiveShadow = true; // Vật thể nhận bóng
scene.add(cube);

Bước 4: Tùy chỉnh bóng đổ

Bạn có thể tùy chỉnh độ phân giải bóng đổ để cải thiện chất lượng:

directionalLight.shadow.mapSize.width = 1024; // Độ phân giải bóng đổ (chiều ngang)
directionalLight.shadow.mapSize.height = 1024; // Độ phân giải bóng đổ (chiều dọc)

Ví dụ đầy đủ: Thêm ánh sáng và bóng đổ

  • Nhấn phím 1 để bật/tắt ánh sáng Ambient Light
  • Nhấn phím 2 để bật/tắt ánh sáng Directional Light
  • Nhấn phím 3 để bật/tắt ánh sáng Spot Light
  • Nhấn phím 4 để bật/tắt ánh sáng Point Light
  • Nhấn phím 5 để bật/tắt ánh sáng Hemisphere Light
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Toggle Lights in Three.js</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r152/three.min.js"></script>
</head>
<body>
  <script type="module">
    import * as THREE from 'https://cdn.skypack.dev/three@0.129.0/build/three.module.js';

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.set(0, 5, 10); // Điều chỉnh camera gần hơn

    const renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    document.body.appendChild(renderer.domElement);

    // Objects
    const plane = new THREE.Mesh(
      new THREE.PlaneGeometry(40, 40),
      new THREE.MeshStandardMaterial({ color: 0x808080 })
    );
    plane.rotation.x = -Math.PI / 2;
    plane.receiveShadow = true;
    scene.add(plane);

    const cube = new THREE.Mesh(
      new THREE.BoxGeometry(2, 2, 2),
      new THREE.MeshStandardMaterial({ color: 0xff0000 })
    );
    cube.position.set(0, 1, 0);
    cube.castShadow = true;
    scene.add(cube);

    // Lights (initially off)
    const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
    ambientLight.visible = false;
    scene.add(ambientLight);

    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
    directionalLight.position.set(5, 10, 5);
    directionalLight.castShadow = true;
    directionalLight.visible = false;
    scene.add(directionalLight);

    const spotLight = new THREE.SpotLight(0xffffff, 0.8);
    spotLight.position.set(-5, 10, 5);
    spotLight.castShadow = true;
    spotLight.angle = Math.PI / 6;
    spotLight.visible = false;
    scene.add(spotLight);

    const pointLight = new THREE.PointLight(0xffffff, 0.8, 30);
    pointLight.position.set(0, 10, -5);
    pointLight.castShadow = true;
    pointLight.visible = false;
    scene.add(pointLight);

    const hemisphereLight = new THREE.HemisphereLight(0xffe0b2, 0xb2d8ff, 0.6);
    hemisphereLight.visible = false;
    scene.add(hemisphereLight);

    // Light Helpers
    const helper1 = new THREE.DirectionalLightHelper(directionalLight, 3);
    const helper2 = new THREE.SpotLightHelper(spotLight);
    const helper3 = new THREE.PointLightHelper(pointLight, 1);
    scene.add(helper1, helper2, helper3);

    // Toggle lights with key presses
    window.addEventListener('keydown', (event) => {
      switch (event.key) {
        case '1': // Ambient Light
          ambientLight.visible = !ambientLight.visible;
          console.log(`Ambient Light: ${ambientLight.visible ? 'On' : 'Off'}`);
          break;
        case '2': // Directional Light
          directionalLight.visible = !directionalLight.visible;
          console.log(`Directional Light: ${directionalLight.visible ? 'On' : 'Off'}`);
          break;
        case '3': // Spot Light
          spotLight.visible = !spotLight.visible;
          console.log(`Spot Light: ${spotLight.visible ? 'On' : 'Off'}`);
          break;
        case '4': // Point Light
          pointLight.visible = !pointLight.visible;
          console.log(`Point Light: ${pointLight.visible ? 'On' : 'Off'}`);
          break;
        case '5': // Hemisphere Light
          hemisphereLight.visible = !hemisphereLight.visible;
          console.log(`Hemisphere Light: ${hemisphereLight.visible ? 'On' : 'Off'}`);
          break;
      }
    });

    // Animation loop
    function animate() {
      requestAnimationFrame(animate);

      // Xoay khối theo trục Y
      cube.rotation.y += 0.01;

      // Render lại cảnh
      renderer.render(scene, camera);
    }
    animate();
  </script>
</body>
</html>

Kết luận

Ánh sáng và bóng đổ là yếu tố then chốt giúp tăng tính chân thực và thẩm mỹ cho các cảnh 3D. Hiểu rõ cách sử dụng các loại ánh sáng trong Three.js sẽ giúp bạn thiết kế các hiệu ứng ánh sáng phù hợp với yêu cầu dự án. Ở bài tiếp theo, chúng ta sẽ tìm hiểu về vật liệu (Materials) và cách làm cho các đối tượng trông sống động hơn.

Website Logo

Với hơn 10 năm kinh nghiệm lập trình web và từng làm việc với nhiều framework, ngôn ngữ như PHP, JavaScript, React, jQuery, CSS, HTML, CakePHP, Laravel..., tôi hy vọng những kiến thức được chia sẻ tại đây sẽ hữu ích và thiết thực cho các bạn.

Bình luận

Website Logo

Chào, tôi là Vũ. Đây là blog hướng dẫn lập trình của tôi.

Liên hệ công việc qua email dưới đây.

lhvuctu@gmail.com

Chúng Tôi Trên

Bạn đang muốn học về lập trình website?

Bạn cần nâng cao kiến thức chuyên nghiệp hơn để nâng cao cơ hội nghề nghiệp? Liên hệ