three.jsをかじる

three.jsは3Dを表示してくれるJavaScriptライブラリだ。

次のサイトで親切な解説をしてくれていたので入門編、基礎編、中級編を読んでみた。コードと一緒にイメージ画像やサンプルがあるので読みやすい。読んでいないが応用編もある。

  • フォグを使うことで奥行きが出せる。
  • スプライトを使うことでどのどの視点から見ても正面を向いている。ポリゴン数を節約できる。
  • ジオメトリの結合を行うことで負荷が少なくなる。ただし、個別のマテリアルやマウスイベントの設定ができない。

上の入門サイトでも紹介されているJHT’s Planetary Pixel Emporiumのサイトの地球、木星、月、土星の画像を使って表示してみた。

平行光源の反射がまぶしかったので暗めに、環境光源も使ってみた。

地球のコード

<canvas id="earth"></canvas>
  <script src="/html/threejs/js/three.min.js"></script>
  <script src="/html/threejs/js/controls/OrbitControls.js"></script>
  <script>
// ページの読み込みを待つ
window.addEventListener('load', earth);

// サイズを指定
const width = 300;
const height = 300;

function earth() {
  // レンダラーを作成
  const renderer = new THREE.WebGLRenderer({
    canvas: document.querySelector('#earth')
  });
  renderer.setSize(width, height);

  // シーンを作成
  const scene = new THREE.Scene();

  // カメラを作成
  const camera = new THREE.PerspectiveCamera(40, width / height, 1, 10000);
  camera.position.set(0, 500, +1000);
  // 原点方向を見つめる
  camera.lookAt(new THREE.Vector3(0, 0, 0));
  // カメラコントローラーを作成
  const controls = new THREE.OrbitControls(camera, renderer.domElement);
  // 滑らかにカメラコントローラーを制御する
  controls.enableDamping = true;
  controls.dampingFactor = 0.2;
  // 球体を作成
  const geometry = new THREE.SphereGeometry(300, 30, 30);
  // 画像を読み込む
  const loader = new THREE.TextureLoader();
  const texture = loader.load('https://blog.t-haku.com/html/threejs/images/earthmap1k.jpg');
  // マテリアルにテクスチャーを設定
  const material = new THREE.MeshStandardMaterial({map: texture});
  // メッシュを作成
  const mesh = new THREE.Mesh(geometry, material);
  // 3D空間にメッシュを追加
  scene.add(mesh);

  // 平行光源
  const directionalLight = new THREE.DirectionalLight(0x333333);
  directionalLight.position.set(1, 1, 1);
  // シーンに追加
  scene.add(directionalLight);
  // 環境光源を作成
  // new THREE.AmbientLight(色, 光の強さ)
  const light = new THREE.AmbientLight(0xffffff, 1.0);
  light.position.set(1, 1, 1);
  scene.add(light);

  tick();

  // 毎フレーム時に実行されるループイベントです
  function tick() {
    // メッシュを回転させる
    mesh.rotation.y += 0.01;
    // カメラコントローラーを更新
    controls.update();
    // レンダリング
    renderer.render(scene, camera);

    requestAnimationFrame(tick);
  }
}  </script>

土星のコード

<canvas id="saturn"></canvas>
  <script>
// ページの読み込みを待つ
window.addEventListener('load', saturn);

// サイズを指定
const width = 300;
const height = 300;

function saturn() {
  // レンダラーを作成
  const renderer = new THREE.WebGLRenderer({
    canvas: document.querySelector('#saturn')
  });
  renderer.setSize(width, height);

  // シーンを作成
  const scene = new THREE.Scene();

  // カメラを作成
  const camera = new THREE.PerspectiveCamera(40, width / height, 1, 10000);
  camera.position.set(0, 500, +1000);
  // 原点方向を見つめる
  camera.lookAt(new THREE.Vector3(0, 0, 0));
  // カメラコントローラーを作成
  const controls = new THREE.OrbitControls(camera, renderer.domElement);
  // 滑らかにカメラコントローラーを制御する
  controls.enableDamping = true;
  controls.dampingFactor = 0.2;
  let scale = 20;

  // 球体を作成
  const geometry = new THREE.SphereGeometry(6*scale, 30, 30);
  // 画像を読み込む
  const loader = new THREE.TextureLoader();
  const texture = loader.load('https://blog.t-haku.com/html/threejs/images/saturnmap.jpg');
  // マテリアルにテクスチャーを設定
  const material = new THREE.MeshStandardMaterial({map: texture});
  // メッシュを作成
  const mesh = new THREE.Mesh(geometry, material);
  // 3D空間にメッシュを追加
  scene.add(mesh);

  // 環
  let ringGeometry = new THREE.TorusGeometry(6*scale*2.26, 6*scale, 2, 1000);
  let ringTexture = THREE.ImageUtils.loadTexture('https://blog.t-haku.com/html/threejs/images/saturnringcolor.jpg');
  ringTexture.rotation = 1.5708; // 90度
  let ringMaterial = new THREE.MeshLambertMaterial( {
	map: ringTexture,
	alphaMap: THREE.ImageUtils.loadTexture('https://blog.t-haku.com/html/threejs/images/saturnringpattern.gif'),
	transparent: true,
	side: THREE.DoubleSide,
  });
  var ringMesh = new THREE.Mesh(ringGeometry, ringMaterial);
  ringMesh.lookAt(new THREE.Vector3(0,1,0));
  mesh.add(ringMesh);

  // 平行光源
  const directionalLight = new THREE.DirectionalLight(0x333333);
  directionalLight.position.set(1, 1, 1);
  // シーンに追加
  scene.add(directionalLight);

  // 環境光源を作成
  // new THREE.AmbientLight(色, 光の強さ)
  const light = new THREE.AmbientLight(0xFFFFFF, 1.0);
  light.position.set(1, 1, 1);
  scene.add(light);

  tick();

  // 毎フレーム時に実行されるループイベントです
  function tick() {
    // メッシュを回転させる
    mesh.rotation.y += 0.01;
    // カメラコントローラーを更新
    controls.update();
    // レンダリング
    renderer.render(scene, camera);

    requestAnimationFrame(tick);
  }
}  </script>