【Three.js】基本のライト:AmbientLight, DirectionalLight, PointLightの使い方とサンプルデモ

2023年11月21日WebGL & Three.js

Three.jsの最も基本的でよく使うライトであるAmbientLight, DirectionalLight, PointLightの使い方を紹介します。
 ライトがない状態のデモがあるとわかりやすいので、ライトなしと、AmbientLight, DirectionalLight, PointLightを使ったサンプルデモを用意しているので、
まずは確認してみてください。

ライトなしと、AmbientLight, DirectionalLight, PointLightを使ったサンプルデモ




ライトの詳しい説明は後で書きますが、
3Dモデルを表示(ライトなし)のデモで黒くなっている部分は、ライトがないと表示されない物体です。
Ambient Lightは全方位から照らされているようなイメージで、ライトが必要な物体がみえるようになります。
Directional Lightは、ライトのあてる方向を決めて並行に照らすことができるライトです。
Pointer Lightは、ある一点から光が照射されるようなライトです。これだけわかりやすいように動かしています。

ソースコード

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );

  const renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 背景色を変更する
  renderer.setClearColor(0xf0f0f0);
  // document.body.appendChild(renderer.domElement);
  document.getElementById("canvas-container").appendChild(renderer.domElement);

  // 床
  const floor = new THREE.Mesh(
    new THREE.PlaneGeometry(1000, 1000),
    new THREE.MeshStandardMaterial({
      color: 0x777777,
      side: THREE.DoubleSide,
    })
  );

  floor.rotation.x = THREE.MathUtils.degToRad(90);
  floor.position.y = -60;
  scene.add(floor);

  // メッシュ作成
  const geometry = new THREE.TorusKnotGeometry(5, 1.4, 160, 160);
  const basic = new THREE.MeshBasicMaterial({ color: 0x3fff9d });
  const lambert = new THREE.MeshLambertMaterial({ color: 0x3fff9d });
  const standard = new THREE.MeshStandardMaterial({
    color: 0x3fff9d,
    roughness: 0,
  });

  const mesh1 = new THREE.Mesh(geometry, basic);
  mesh1.position.x -= 20;

  const mesh2 = new THREE.Mesh(geometry, lambert);

  const mesh3 = new THREE.Mesh(geometry, standard);
  mesh3.position.x += 20;

  scene.add(mesh1, mesh2, mesh3);

  // 軸ヘルパー
  const axis = new THREE.AxesHelper(1000);
  scene.add(axis);

  camera.position.z = 40;

  const control = new OrbitControls(camera, renderer.domElement);

  // ライト
  // AmbientLight参考: https://threejs.org/docs/index.html?q=ambi#api/en/lights/AmbientLight
  // AmbientLight:シーン全体を全方位から均等に照らすライト
  const ambientLight = new THREE.AmbientLight(0xf0f0f0);
  scene.add(ambientLight);
  // DirectionalLight参考: https://threejs.org/docs/index.html?q=directional#api/en/lights/DirectionalLight
  // DirectionalLight: 並行に照らすライト
  // 第一引数:色、第二引数:強度
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
  // ライトをあてる方向を指定できる
  // x,y,z軸をそれぞれ設定し、そこから原点(0,0,0)に向かってライトが照らされる
  directionalLight.position.set(0, 10, 10);
  // 原点(0,0,0)に向かって照らすのではなくズラしたいときはtargetを使う
  directionalLight.target.position.set(5, 0, 0);

  // ライトのヘルパー
  // ライトがどこから照らされているのかを見えやすくする
  // 白い四角と線でみえる
  const dHelper = new THREE.DirectionalLightHelper(directionalLight);
  scene.add(directionalLight,directionalLight.target,  dHelper);

  // 点光源
  const pointLight = new THREE.PointLight(0xffffff, 1, 200);
  pointLight.position.set(0, 0, 4);

  // 回転させる
  // radius, phi(x軸への回転), theta(y軸への回転)
  const spherical = new THREE.Spherical(22, 1, 1);
  pointLight.position.setFromSpherical(spherical);

  // 点光源のヘルパー
  const pHelper = new THREE.PointLightHelper(pointLight);
  scene.add(pointLight, pHelper);

  function animate() {
    requestAnimationFrame(animate);
    // 点光源を回転させる
    spherical.phi += 0.01;
    spherical.theta += 0.01;
    pointLight.position.setFromSpherical(spherical);
    // ヘルパーの向きを整える
    dHelper.update();
    control.update();

    renderer.render(scene, camera);
  }

  animate();

もしThree.jsの基本的な操作の一連の流れを知らないという場合は、Three.jsの基本的な操作の一連の流れがとても短くまとめた記事なので参考にしてみてください。
具体的なコードとデモが見たい場合は、【WebGL&Three.js入門】Three.jsの一番シンプルなサンプルコードのチュートリアルの解説でデモもみれる状態にしているので参考にしてみてください。
コードのポイントは以下です。

ジオメトリ

今回は、TorusKnotGeometryを使用しています。複雑な形なので、ライトがよりわかりやすくなるためです。
あと、反射するライトがあるため、PlaneGeometryで下に平面し、床を作成しています。
床にあたるコードは以下の部分です。

  const floor = new THREE.Mesh(
    new THREE.PlaneGeometry(1000, 1000),
    new THREE.MeshStandardMaterial({
      color: 0x777777,
      side: THREE.DoubleSide,
    })
  );

  floor.rotation.x = THREE.MathUtils.degToRad(90);
  floor.position.y = -60;
  scene.add(floor);

THREE.Mathという記述がある場合、Three.jsバージョン(0.152.0)からはTHREE.MathUtilsとなります。
Three.jsではradianで定義しているので、90度などの度数を使いたい場合は、度数法に変換する必要があります。
degToRad()は、弧度法(Radian)を度数法(Degree)に変換する関数です。
具体的には、radian = degree * Math.PI / 180;で変換できます。
引数に傾けたい度数(例: 90)を入れれば、90度傾けられる
参考: https://threejs.org/docs/#api/en/math/MathUtils.degToRad

マテリアル

物体には、それぞれ左から、MeshBasicMaterial、MeshLambertMaterial、MeshStandardMaterialを使用しています。
床にはMeshStandardMaterialを使用しています。
MeshBasicMaterialはライトを必要としません。
MeshLambertMaterialとMeshStandardMaterialは、ライトを必要とします。
デモの3Dモデルを表示(ライトなし)をみるとその違いが一目瞭然でわかります。
また、MeshLambertMaterialはマットな感じになり、MeshStandardMaterialは光沢を表現できます。
roughnessをいじることで光沢の度合いを調整することができます。

AmbientLightの使い方

  // ライト
  const ambientLight = new THREE.AmbientLight(0xf0f0f0);
  scene.add(ambientLight);

AmbientLight参考: https://threejs.org/docs/index.html?q=ambi#api/en/lights/AmbientLight
AmbientLightは、シーン全体を全方位から均等に照らすライトです。
反射とかはしません。
AmbientLightをあてることで、どのメッシュ(物体)も色がみえるようになります。(デモ参照)

DirectionalLightの使い方

  // DirectionalLight
  // DirectionalLight: 並行に照らすライト
  // 第一引数:色、第二引数:強度
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
  // ライトをあてる方向を指定できる
  // x,y,z軸をそれぞれ設定し、そこから原点(0,0,0)に向かってライトが照らされる
  directionalLight.position.set(0, 10, 10);
  // 原点(0,0,0)に向かって照らすのではなくズラしたいときはtargetを使う
  directionalLight.target.position.set(5, 0, 0);

  // ライトのヘルパー
  // ライトがどこから照らされているのかを見えやすくする
  // 白い四角と線でみえる
  const dHelper = new THREE.DirectionalLightHelper(directionalLight);
  scene.add(directionalLight,directionalLight.target,  dHelper);

  function animate() {
    // ヘルパーの向きを整える
    dHelper.update();
    ...
  }

DirectionalLight参考: https://threejs.org/docs/index.html?q=directional#api/en/lights/DirectionalLight
DirectionalLightは、並行に照らすライトです。
第一引数:色、第二引数:強度をとります。
ライトをあてる方向を指定できます。
x,y,z軸をそれぞれ設定し、そこから原点(0,0,0)に向かってライトが照らされます。
また、原点(0,0,0)に向かって照らすのではなくズラしたいときはtargetのpositionを変更することで可能になります。
その場合は、targetもシーンに追加します。

そして、ライトがどこから照らされているのかを見えやすくしたい場合は、ライトのヘルパーが存在します。(DirectionalLightHelper)
上のように、セットしたら、忘れずに、animate()の中でそのヘルパーをupdate()で更新してあげる必要があります。

PointLightの使い方

  // 点光源
  const pointLight = new THREE.PointLight(0xffffff, 1, 200);
  pointLight.position.set(0, 0, 4);

  // 回転させる
  // radius, phi(x軸への回転), theta(y軸への回転)
  const spherical = new THREE.Spherical(22, 1, 1);
  pointLight.position.setFromSpherical(spherical);

  // 点光源のヘルパー
  const pHelper = new THREE.PointLightHelper(pointLight);
  scene.add(pointLight, pHelper);

  function animate() {
    ...
    // 点光源を回転させる
    spherical.phi += 0.01;
    spherical.theta += 0.01;
    pointLight.position.setFromSpherical(spherical);
    ...
  }

PointLightは点からライトを照射するような感じです。(デモ参照)
PointLight参考:https://threejs.org/docs/index.html?q=pointLi#api/en/lights/PointLight
こちらもヘルパーがあるので、PointLightHelperを使ってどこに点光源があるのかをヘルパーでしめすことができます。
また、この点光源はよく動かしたり、回転させたりします。
その方法も上に記述していますが、
Sphericalをインスタンス化します。Sphericalは、radius, phi(x軸への回転), theta(y軸への回転)を引数にとります。
このphiやthetaの値を変更することで、ライトを動かすことができます。
具体的には、animate()の以下の記述です。

spherical.phi += 0.01;
    spherical.theta += 0.01;
    pointLight.position.setFromSpherical(spherical);