クモのようにコツコツと

フロントエンドエンジニア イイダリョウのブログ。略称「クモコツ」

【Three.js】マテリアルとライティング設定(入門編に再入門!)

Three.jsの続きです。前回はThree.js入門のの回る箱をいろいろ打ち替えてみました。今回は「マテリアル」と「ライティング」を見てきます。それでは行きましょう!

【目次】

前回記事
※参考:【Three.js】回る箱をいろいろ打ち替えてみる - クモのようにコツコツと

Three.jsを習得するためにやったことまとめ
qiita.com

入門編の「回る箱」おさらい

ICS「Three.js入門」の「入門編」で作った回る箱。

See the Pen three.js 01 by イイダリョウ (@i_ryo) on CodePen.

※参考:簡単なThree.jsのサンプルを試そう - ICS MEDIA

JSコード

// ページの読み込みを待つ
    window.addEventListener('load', init);

    function init() {

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

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

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

      // カメラを作成
      const camera = new THREE.PerspectiveCamera(45, width / height);
      camera.position.set(0, 0, +1000);

      // 箱を作成
      const geometry = new THREE.BoxGeometry(400, 400, 400);
      const material = new THREE.MeshNormalMaterial();
      const box = new THREE.Mesh(geometry, material);
      scene.add(box);

      tick();

      // 毎フレーム時に実行されるループイベントです
      function tick() {
        box.rotation.y += 0.01;
        renderer.render(scene, camera); // レンダリング

        requestAnimationFrame(tick);
      }
    }

マテリアルとは何か

今回はその続き、「Three.jsのマテリアルの基本」を見ていく。

※参考:Three.jsのマテリアルの基本 - ICS MEDIA

まずマテリアルとは何か?*1

該当ページにはこうある。

マテリアルとは物体の質感設定のことです。
代表的なマテリアルとして「単色塗りのマテリアル」と「画像を使ったマテリアル」の二種類があります。

なお、よく似た単語に「シェーダー」「テクスチャ」もある。

マテリアル
モデル表面の反射率や粗さなど、描画設定の集まり。

テクスチャ
色や模様を表現するビットマップ画像。

シェーダー
ピクセル毎の描画色を計算するスクリプト。

テクスチャは画像でシェーダーは設定値でその両方を含む表面の描画設定がマテリアルか。

※参考:マテリアルとシェーダーとテクスチャの違い

Three.jsのオブジェクト作成手順

Three.js入門の該当ページにはこうある。

Three.jsのオブジェクトの作成手順 ①マテリアルを作成 ②ジオメトリを作成 ③メッシュを作成

またわからない言葉が出てきた。ジオメトリとはなんぞや?メッシュとは?

Three.js入門の次ページ「ジオメトリ」に解説があった。

形状(ジオメトリとも言います)を指定することで「球体」や「直方体」、「平面」などさまざまな3Dのオブジェクトを表示できます

Three.jsでは形状とマテリアルを結合しメッシュを作成することによって、表示可能な3Dのオブジェクトを得ることができます。

※参考:Three.jsのジオメトリの基本 - ICS MEDIA

表面の描画設定(マテリアル)と形状(ジオメトリ)を結合して作成したメッシュがオブジェクトになると。

ジオメトリには馴染みはなかったが3DCGでも一般的な言葉のようだ。

ジオメトリとは、幾何学、形状、などの意味を持つ英単語。コンピュータグラフィックスにおける描画対象の形状や、形状を定義づける頂点の座標や線分、面などの図形を表す式の係数といったデータの組み合わせを意味することが多い。

※参考:ジオメトリとは - IT用語辞典 e-Words

メッシュについては「ポリゴンの集まり」という意味があるようだ。

ポリゴン:多角形のこと(三角形、四角形、五角形・・etc)
メッシュ:ポリゴンの集まりのこと
サーフェス:面のこと

※参考:ポリゴン・メッシュ・サーフェスの違い

ジオメトリを箱から球体に

変数geometryを変更

// ジオメトリを作成(球体)
      const geometry = new THREE.SphereGeometry(300, 30, 30);

THREE.BoxGeometry()クラスをTHREE.SphereGeometry()クラスに変更した。

変数名boxも形状に影響されないようにmeshに変更した。

    //メッシュを作成
    const mesh = new THREE.Mesh(geometry, material);

変数boxが適用されている場所が二箇所あったので変更する。

      //シーンにメッシュを適用
      scene.add(mesh);
// 毎フレーム時に実行されるループイベントです
      function tick() {
        mesh.rotation.y += 0.01;
        renderer.render(scene, camera); // レンダリング

回る箱が球体になった!

See the Pen three.js 15 by イイダリョウ (@i_ryo) on CodePen.

マテリアルを赤色に

次、マテリアルの設定

    // マテリアルを作成
      const material = new THREE.MeshStandardMaterial({color: 0xFF0000});

変数materialTHREE.MeshNormalMaterial()クラスをTHREE.MeshStandardMaterial()クラスに変更。引数は連想配列でcolorキーの値は0xFF0000(RGBの赤色を意味する)

さあどうだ!

See the Pen three.js 16 by イイダリョウ (@i_ryo) on CodePen.

お、真っ暗になってしまった。。

Three.jsの「マテリアル」の記事にTHREE.MeshNormalMaterial()の解説があった。

THREE.MeshNormalMaterialクラスはノーマルのカラーをRGBで可視化するマテリアルです。ライティングを必要としないため、手軽に動作確認するときに役立つでしょう。

※参考:Three.jsのさまざまなマテリアル - ICS MEDIA

THREE.MeshNormalMaterial()クラスは自ら光っているのでライトが必要なかったわけだ。通常のマテリアル設定ではライティングを設定しないと真っ暗になってしまう。

ライティング設定

ということでライティングを設定する。オブジェクトに光を当てるって実写的にで3Dならではな感じがするなぁ。

  // 平行光源
  const directionalLight = new THREE.DirectionalLight(0xFFFFFF);
  directionalLight.position.set(1, 1, 1);
  // シーンに追加
  scene.add(directionalLight);
  • 変数directionalLightTHREE.DirectionalLight()クラスを代入。引数は0xFFFFFF(白色)
  • directionalLightpositionオブジェクトのset()メソッドに引数を3つ(いずれも値は1)
  • scenedirectionalLightを追加する

THREE.DirectionalLightクラス
平行光源。ライトの位置と方向を指定し平行に到達する光として使用できます。

THREE.DirectionalLightは一箇所から直線上に照らしている光。太陽とか電灯みたいなイメージ。

THREE.AmbientLightクラス
環境光。空間全体を照らす光として使用できます。

ちなみに環境光というのもあるらしい(今回は書いていない)

さあどうだ!

See the Pen three.js 17 by イイダリョウ (@i_ryo) on CodePen.

お、赤い球体が出てきた!

マテリアルに画像を配置する

最後に、マテリアルを色ではなくビットマップ画像を配置してみる。

      // 画像を読み込む
      const loader = new THREE.TextureLoader();
      const texture = loader.load('(画像パス)/hoge.jpg');
      // マテリアルを作成
      const material = new THREE.MeshStandardMaterial({map: texture});
  • 変数loaderTHREE.TextureLoader()クラスを代入
  • 変数textureloaderload()メソッドで画像ファイルを読み込み
  • 変数materialTHREE.MeshStandardMaterial()クラスの引数をmapキーに変更し、値をtexture

これで先ほどの赤色がビットマップ画像になる。どうだ!

See the Pen three.js 18 by イイダリョウ (@i_ryo) on CodePen.

やた!イイダリョウのプロフィール画像(風街ばあじょん)が貼られた!

JSコードはこんなんなりました。

// ページの読み込みを待つ
    window.addEventListener('load', init);

    function init() {

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

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

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

      // カメラを作成
      const camera = new THREE.PerspectiveCamera(45, width / height);
      camera.position.set(0, 0, +1000);

      // ジオメトリを作成(球体)
      const geometry = new THREE.SphereGeometry(300, 30, 30);
      // 画像を読み込む
      const loader = new THREE.TextureLoader();
      const texture = loader.load('https://s.cdpn.io/profiles/user/305282/512.jpg');
      // マテリアルを作成
      const material = new THREE.MeshStandardMaterial({map: texture});
      //メッシュを作成
      const mesh = new THREE.Mesh(geometry, material);
      //シーンにメッシュを適用
      scene.add(mesh);
      
        // 平行光源
  const directionalLight = new THREE.DirectionalLight(0xFFFFFF);
  directionalLight.position.set(1, 1, 1);
  // シーンに追加
  scene.add(directionalLight);
      

      tick();

      // 毎フレーム時に実行されるループイベントです
      function tick() {
        mesh.rotation.y += 0.01;
        renderer.render(scene, camera); // レンダリング

        requestAnimationFrame(tick);
      }
    }

最後に

f:id:idr_zz:20200109185527p:plain

ということでThree.js入門に再入門しました。なんと、前回は2018年!昨年はVue.jsに集中したため1年以上空いてしまった。。

その間、長めのJSコードに触れる機会も多く、当時よりコードの読解力が増えたように感じました。今度こそ中段せずにコンスタントに継続して行きたく思います。

次回は入門編の続き「ジオメトリ」を見て行きたく思います。それではまた!


Three.jsを習得するためにやったことまとめ
qiita.com

*1:待て、リアル(現実)、なんてダジャレを言っている場合ではない!