Developer's Blog

3D 初心者が Three.js を触ってみた

こんにちは。ウェブ共同開発部の鍋良です。

諸々あって「Three.js で遊んでみたい!」という気持ちが芽生えまして、先日初めて Three.js を触ってみました。自分なりに調べつつ基本の「き」を学びましたので、Three.js での 3D レンダリングについて簡単にまとめたいと思います。

内容は目新しくありませんが、「Three.js で 3D やってみたいけど、ハードル高そうだな……」と躊躇されている方にご一読いただけると幸いです。

 

Three.js

WebGL を JavaScript で扱えるライブラリです。
3D グラフィックスを比較的簡単に作成できるライブラリとして有名です。
公式ドキュメントは英語ですが、日本語の参考書籍や記事もそこそこ多いので、私のような初心者でも学びやすくなっています。

準備

はじめに Three.js 本体を用意します。
公式サイトからダウンロードしてもいいですし、CDN から読み込んでもいいです。
今回はお手軽に CDN から読み込むことにします。

HTML スケルトンには Div 要素を一つ用意します。
ここに 3D グラフィックスが描画されるよう、JavaScript で設定を追加していきます。

sample.html

<!DOCTYPE html>
<html>
  <head>
    <title>Three.js Sample</title>
  </head>
  <body>
    <div id="sample"></div>
    <script src="https://ajax.googleapis.com/ajax/libs/threejs/r84/three.min.js">
    </script>
    <script>
      function init() {
        // ここにサンプルコードを追記していきます
      }
      window.onload = init();
    </script>
  </body>
</html>

基本構成

3D グラフィックスを表示するために必要となる大まかな設定は、下記のとおりです。

  • シーン(舞台)
  • カメラ
  • メッシュ(物体)
  • ライト(材質)
  • レンダラー(レンダリング)

これだけ述べると何が何やら……ですね。
それではシーンから順番に、簡単な説明を交えて設定していきます。

シーン

シーンとは物体や光源を配置できるコンテナオブジェクトのことです。
3D 空間といったほうが、ニュアンス的に伝わりやすいかもしれません。
シーンがなければ 3D グラフィックスが描画できませんので、最初に設定しましょう。

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

カメラ

カメラの設定では、シーンを描画する際に何をどう見るか指定することができます。
Three.js のカメラは2種類あり、違いは下記のとおりです。

透視投影カメラ:視点より遠いものは小さく、近いものは大きく映るカメラ
並行投影カメラ:視点との距離に関係なく、物体が常に同じ大きさで映るカメラ

個人的に遠近感が欲しいので、今回は透視投影の PerspectiveCamera 関数を使います。
一緒にカメラの位置と向きを設定しましょう。

// カメラ
// new THREE.PerspectiveCamera(画角、アスペクト比、描画開始距離、描画終了距離)
const camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 1, 1000);

// カメラの位置設定は、camera.position.set(x,y,z) と書くこともできます
camera.position.x = 200;
camera.position.y = 100;
camera.position.z = 300;

// カメラの向きを中央(原点座標)に設定
camera.lookAt({x:0, y:0, z:0 });

PerspectiveCamera 関数で設定する値の補足説明はこちら。
画角:カメラから見える範囲を角度で示したもの
アスペクト比:縦横比
描画開始距離:カメラが描画を始める一番近い位置
描画終了距離:カメラが描画を終える一番遠い位置

メッシュ

メッシュとは物体のことで、ここで設定したメッシュがシーンに配置されます。
メッシュを作成するとき、ジオメトリ(形状)とマテリアル(材質)を指定する必要があります。

Three.js には「丸」「立方体」などの基本的なジオメトリが用意されていますので、今回は「立方体」を使うことにします。
もちろん自作の 3D モデルを読み込ませることもできますので、慣れたらぜひ試したいところです。

// ジオメトリ
// new THREE.BoxGeometry(幅, 高さ, 奥行き)
const geometry = new THREE.BoxGeometry(50, 50, 50);

マテリアルは様々な種類が用意されており、それぞれ表現できる内容が異なります。
今回はライトに反応してくれる MeshLambertMaterial というマテリアルを使います。
MeshLambertMaterial は、メッシュの質感を光沢感のないくすんだ感じで表現してくれます。

// マテリアル
// new THREE.MeshLambertMaterial({color: マテリアルが発する色})
const material = new THREE.MeshLambertMaterial({color: 0xd5595f});

ジオメトリとマテリアルが設定できたらメッシュ関数に渡し、シーンに追加します。

// メッシュ
// new THREE.Mesh(ジオメトリ, マテリアル)
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

まだ画面には表示されませんが、これで赤い立方体がシーンに配置されました。

ライト

ライトは光源のことです。
ライトがないとシーン内に描画されるものが見えないので、設定しましょう。

マテリアルと同じく、ライトにもいくつか種類が用意されています。
今回は使う場面が多いとされる、DirectionalLight を使います。
DirectionalLight では「平行光源」という、光源面から平行に向けられる光を設定することができます。
よく太陽光に近いと例えられていますね。

ライトと位置を設定したら、シーンに追加します。

// ライト
// new THREE.DirectionalLight(色)
const light = new THREE.DirectionalLight(0xffffff);

// ライトの位置設定は、light.position.set(x,y,z) と書くこともできます
light.position.x = 0;
light.position.y = 100;
light.position.z = 50;

scene.add(light);

レンダラー

最後にレンダリングを行います。
作成したシーンとカメラを HTML に紐づけることで、初めて画面に描画されるようになります。

使用するレンダラーは、Three.js に用意されている WebGLRenderer です。
レンダラーを生成する際、オプションでアンチエイリアスを設定すると、描画される 3D グラフィックスがなめらかに表示されます。

// レンダラー
const renderer = new THREE.WebGLRenderer({antialias: true});

シーンの大きさと背景色の設定も行い、HTML スケルトンに用意していた Div 要素にレンダラーの出力を追加します。

// シーンの大きさ
renderer.setSize(window.innerWidth, window.innerHeight);

// 背景色
renderer.setClearColor(0xf8f8f8);

// Div 要素にレンダラーの出力を追加
document.getElementById('sample').appendChild(renderer.domElement);

そのあとレンダラーにカメラオブジェクトを渡して、シーンを表示するように指示します。

// カメラでシーンを表示するよう指示
renderer.render(scene, camera);

これで、画面に 3D グラフィックスが表示されるようになります。

コード全文

今までのコードをまとめると、下記のようになります。

function init() {
  // シーン
  const scene = new THREE.Scene();

  // カメラ
  const camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 1, 1000);
  camera.position.x = 100;
  camera.position.y = 100;
  camera.position.z = 150;
  camera.lookAt({x:0, y:0, z:0 });

  // メッシュ
  const geometry = new THREE.BoxGeometry(50, 50, 50);
  const material = new THREE.MeshLambertMaterial({color: 0xd5595f});
  const cube = new THREE.Mesh(geometry, material);
  scene.add(cube);

  // ライト
  const light = new THREE.DirectionalLight(0xffffff);
  light.position.x = 0;
  light.position.y = 100;
  light.position.z = 50;
  scene.add(light);

  // レンダラー
  const renderer = new THREE.WebGLRenderer({antialias: true});
  renderer.setSize( window.innerWidth, window.innerHeight );
  renderer.setClearColor(0xf8f8f8);
  document.getElementById('sample').appendChild(renderer.domElement);
  renderer.render(scene, camera);
}

実行

画面中央に赤い立方体が表示されれば、Three.js チャレンジは成功です。
お疲れ様でした!

画面中央に赤い立方体が表示されれば、Three.js チャレンジは成功です。

(追記 1/17 11:25 画像を修正いたしました)

おわりに

今回は Three.js を使った 3D レンダリングについて、簡単にまとめさせていただきました。
実際にコンテンツとして昇華するには、3D モデルやアニメーション、物理演算など、学ぶべき分野がたくさんありますが、「とにかく 3D やってみたい!」という方には、Three.js はおすすめのライブラリです。
3D に興味がある方はぜひ触ってみてくださいね!


フェンリルのオフィシャル Twitter アカウントでは、フェンリルプロダクトの最新情報などをつぶやいています。よろしければフォローしてください!


Copyright © 2019 Fenrir Inc. All rights reserved.