【初学者向け】Three.jsで3Dオブジェクトの表示しよう!

はじめに

この記事の概要

こんにちは、株式会社TOKOSのスギタです!
今回はThree.js 前回準備した表示環境に3Dオブジェクトを表示していきたいと思います。
Three.jsを触ったことない方に向けて解説しますので、最後まで見ていただけると幸いです!

この記事では、以下の内容について詳しく解説します:

  1. Three.jsの初期準備

前回の記事はこちら :

対象読者

  • Three.jsを使用したことのない方
  • JavaScriptを用いたアニメーションに興味のある方

この記事で扱う内容、扱わない内容

この記事で扱う内容:

  • 光源に解説
  • 3Dオブジェクト(Geometry・Material・Mesh)の解説

この記事で扱わない内容:

  • JavaScriptの基本的な仕様方法

今回の成果物

今回は天体をイメージした3Dオブジェクトの表示を目標とします。
以前の記事は3Dオブジェクトを表示するための「舞台」を準備しました。
その「舞台」に対して3Dオブジェクトを追加していく作業になります!

前回の振り返りと調整

前回最終で解説したコードから少し調整していきます。

Three.jsで3Dシーンをスムーズにアニメーション化するために毎フレームごとにレンダリングさせる必要があります。
scene,camera,rendererをグローバルで宣言してから、requestAnimationFrame()メソッドを使用して再帰的に呼び出します。

また、rendererを調整します。
様々なモニターの解像度に最適に表示させるためにsetPixelRatio()メソッドを使用します。
setPixelRatio()メソッドは論理ピクセルに対する物理ピクセルの倍率を指定するメソッドになります。
フルHD(1920✕1080)だった場合はsetPixelRatio(1) 、 4Kだった場合はsetPixelRatio(2) となります。
今回は様々な解像度に対して最適に表示させたいため、引数にはwindow.devicePixelRatio()メソッドで取得した値を渡します。
更に今回は背景を黒色にしたいためsetClearColor()メソッドで背景色を指定します。
第一引数にカラー番号を指定します(今回は16進数)。第二引数に透明度になります。

JavaScript
let scene, camera, renderer;

window.addEventListener("load", init);

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

  // カメラ
  camera = new THREE.PerspectiveCamera(
    50, //視野角
    window.innerWidth / window.innerHeight, //アスペクト比
    0.1, //開始地点
    1000 //終了地点
  );
  
  //レンダラー
  renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);
  renderer.setPixelRatio(devicePixelRatio); //デバイスの解像度に最適化する
  renderer.setClearColor(0x000000, 1); //背景色を黒に設定(第1引数:色、第2引数:透明度)
}
  

function animate() {
  // フレーム単位でアニメーションを読み込む
  requestAnimationFrame(animate);
  //レンダリングの記述
  renderer.render(scene, camera);
}

これで一旦準備完了です。

3Dオブジェクトの概要

ここから準備した「舞台」に対して3Dオブジェクトを追加します。
追加する前に重要な3つの概念を解説します。

Three.jsで3Dオブジェクトを作成する場合は、Geometry(ジオメトリ)・Material(マテリアル)を指定して作成出来ます。
Geometry = 形状
Material = 見た目
だと思ってください。
またこの2つを合わせたものが3Dオブジェクトになります。
この2つを合わせた3DオブジェクトをMesh(メッシュ)といいます。

Geometry(ジオメトリ)の概要

Geometry = 形状と言いました。
「円」や「四角形」などGeometoryで3Dオブジェクトの「形状」を決めます。
Three.jsでは様々なGeometoryが用意されています。
例えばですが、四角形にBoxGeometry() メソッド 、円形だった場合はCircleGeometry() のようにある程度用意されています。

基本的なGeometory :

  • BoxGeometry: 直方体/立方体を作成
  • SphereGeometry: 球体を作成
  • CylinderGeometry: 円柱を作成
  • PlaneGeometry: 平面を作成
  • CircleGeometry: 円形の平面を作成
  • ConeGeometry: 円錐を作成
  • TorusGeometry: ドーナツ形状を作成
  • RingGeometry: 中空の円形を作成

より高度なGeometory :

  • BoxGeometry: 直方体/立方体を作成
  • SphereGeometry: 球体を作成
  • CylinderGeometry: 円柱を作成
  • PlaneGeometry: 平面を作成
  • CircleGeometry: 円形の平面を作成
  • ConeGeometry: 円錐を作成
  • TorusGeometry: ドーナツ形状を作成
  • RingGeometry: 中空の円形を作成

気になる方は下記公式ドキュメントを参照してください。

Material(マテリアル)の概要

Material = 見た目と言いました。
3Dオブジェクトを「紙素材にしたい」や「金属素材にしたい」など3Dオブジェクトの見た目に関わることを決めます。
具体的には「色」「金属度」「鏡面度」「反射率」など細かく設定出来ます。
また読み込んだ画像素材を使用することも出来ます。

Materialメソッド一覧 :

  • MeshBasicMaterial
    • 最もシンプルで軽量
    • ライティングの影響を受けない
    • 単色、ワイヤーフレーム、テクスチャマッピングが可能
  • MeshStandardMaterial
    • roughness(粗さ)とmetalness(金属度)をサポート
    • 物理ベースレンダリング(PBR)対応
    • 現代的なゲームエンジンライクな表現が可能
  • MeshPhysicalMaterial
    • MeshStandardMaterialの拡張版
    • clearcoat、transmission、sheenなどの高度な物理特性をサポート
    • フォトリアルな表現が可能
  • MeshPhongMaterial
    • 光沢のある表面を表現
    • 鏡面反射(specular)のコントロールが可能
    • 比較的軽量で一般的な3D表現に適している
  • MeshLambertMaterial
    • マットな表面を表現
    • 計算が軽量
    • 光沢のない物体の表現に適している
  • MeshToonMaterial
    • セルシェーディング(アニメ調)の表現
    • 段階的な陰影表現が可能
  • MeshNormalMaterial
    • 法線(normal)を色として表示
    • デバッグ用途によく使用される
  • MeshDepthMaterial
    • カメラからの距離を白黒のグラデーションで表現
    • デプスマップの生成などに使用
  • MeshMatcapMaterial
    • 事前計算された材質球の画像を使用
    • 軽量で高品質な表現が可能
  • ShaderMaterial
    • 完全にカスタマイズ可能な表現
    • カスタムシェーダーを使用可能
  • RawShaderMaterial
    • ShaderMaterialの派生
    • Three.jsの組み込みユニフォームやアトリビュートを含まない純粋なシェーダー
  • LineBasicMaterial
    • 線を描画するための基本マテリアル
  • LineDashedMaterial
    • 破線を描画するためのマテリアル
  • PointsMaterial
    • パーティクル(点群)表示用のマテリアル
  • SpriteMaterial
    • スプライト(常にカメラの方を向く平面)用のマテリアル
  • ShadowMaterial
    • 影のみを表示するための特殊なマテリアル

Mesh(メッシュ)の概要

形状(Geometry)と見た目(Material)をあわせたものになります。
Geometry + Materiak = Meshとなります。
準備した「舞台」にはMeshを表示することになります。

Meshの作成

ここからは実際にコードを書いていきます。
今回は成果物は球体で少し金属感にしています。

Geometry(ジオメトリ)の作成

今回形状は球体です。
SphereGeometry() を使用します。

JavaScript
//ジオメトリ
let ballGeometry = new THREE.SphereGeometry(100, 64, 32); //球体のジオメトリの設定 

SphereGeometry() 全てで7つ引数を渡すことが出来ます。今回は第三引数までしか使用しません。

引数について :

  • 第一引数
    • radius(半径)
    • 球体の大きさ
    • デフォルト値: 1
  • 第二引数
    • widthSegments(水平方向の分割数)
    • 球体の水平方向の分割数
    • 大きいほど滑らかになるが、処理が重くなる
    • デフォルト値: 32
  • 第三引数
    • heightSegments(垂直方向の分割数)
    • 球体の垂直方向の分割数
    • 大きいほど滑らかになるが、処理が重くなる
    • デフォルト値: 16

他の引数が引数が知りたい方は下記公式ドキュメントを参照してください。
デモも用意してあるため、触って調整してください。

Material(マテリアル)の作成

ここからMaterialの作成を行います。
今回は金属感を出したいためMeshPhysicalMaterial() を使用します。
また、縞々模様には画像を使用したいと思います。
下記よりダウンロードしてください。

JavaScript
//マテリアル
let ballMaterial = new THREE.MeshPhysicalMaterial({
  color: 0x66ffff, // 青色を追加
  metalness: 0.4, // 金属度を低く設定
  roughness: 0.5, // 粗さを中程度に設定
});

引数にはオブジェクトで渡します。
今回は色をcolorで指定して、matalnessで指定して、roughnessで調整しています。
この他にもかなり細かく指定できます。
ここでは一覧表示も出来ない位なので、下記を参照してください。

更に今回は画像を使用して模様を追加します。

JavaScript
//マテリアル
let texture = new THREE.TextureLoader().load("./textures/Water.jpg"); //画像の読み込み
let ballMaterial = new THREE.MeshPhysicalMaterial({
  map: texture, // 画像の指定
  color: 0x66ffff, // 青色を追加
  metalness: 0.4, // 金属度を低く設定
  roughness: 0.5, // 粗さを中程度に設定
});

画像は下記よりダウンロードしてください。

Mesh(メッシュ)の作成・sceneに追加

作成した、GeometryとMaterialを使用してMeshを作成します。

JavaScript
 //メッシュ = ジオメトリ + マテリアル
  let ballMesh = new THREE.Mesh(ballGeometry, ballMaterial);

  //シーンに追加
  scene.add(ballMesh);

これで完成です。

下記が一旦の全体のコードです。

JavaScript
let scene, camera, renderer;

window.addEventListener("load", init);

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

  // カメラ
  camera = new THREE.PerspectiveCamera(
    50, //視野角
    window.innerWidth / window.innerHeight, //アスペクト比
    0.1, //開始地点
    1000 //終了地点
  );
  
  //レンダラー
  renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);
  renderer.setPixelRatio(devicePixelRatio); //デバイスの解像度に最適化する
  renderer.setClearColor(0x000000, 1); //背景色を黒に設定(第1引数:色、第2引数:透明度)
  
   //ジオメトリ
  let ballGeometry = new THREE.SphereGeometry(100, 64, 32); //球体のジオメトリの設定 
  
  //マテリアル
  let ballMaterial = new THREE.MeshPhysicalMaterial({
    color: 0x66ffff, // 青色を追加
    metalness: 0.4, // 金属度を低く設定
    roughness: 0.5, // 粗さを中程度に設定
  });
  
  //マテリアル
  let texture = new THREE.TextureLoader().load("./textures/Water.jpg"); //画像の読み込み
  let ballMaterial = new THREE.MeshPhysicalMaterial({
    map: texture, // 画像の指定
    color: 0x66ffff, // 青色を追加
    metalness: 0.4, // 金属度を低く設定
    roughness: 0.5, // 粗さを中程度に設定
  });
}
  

function animate() {
  // フレーム単位でアニメーションを読み込む
  requestAnimationFrame(animate);
  //レンダリングの記述
  renderer.render(scene, camera);
}

光源の追加とカメラの調整

今ブラウザを見ても何も写っていないと思います。
なぜ作成した3Dオブジェクトが見えないかと言うと明かりが無いためです。
ここから表示するための「光源」を追加していきたいと思います。
光源もThree.jsでは重要な要素になります。
今回はとりあえず表示したいだけなので、「環境光」をinit関数に追加します。(次回は光源について深堀りします)

JavaScript
//環境光の追加
let ambientLight = new THREE.AmbientLight(0xffffff, 0.8);
scene.add(ambientLight);

更にカメラの位置を調整します。

JavaScript
//カメラの位置の変更
camera.position.set(0, 0, +500);

第一引数はX軸・第二引数はY軸・第三引数はZ軸になります。

最終的なコード

下記が今回の最終的なコードになります。

JavaScript
let scene, camera, renderer;

window.addEventListener("load", init);

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

  // カメラ
  camera = new THREE.PerspectiveCamera(
    50, //視野角
    window.innerWidth / window.innerHeight, //アスペクト比
    0.1, //開始地点
    1000 //終了地点
  );
  //カメラの位置の変更
  camera.position.set(0, 0, +500);
  
  //レンダラー
  renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);
  renderer.setPixelRatio(devicePixelRatio); //デバイスの解像度に最適化する
  renderer.setClearColor(0x000000, 1); //背景色を黒に設定(第1引数:色、第2引数:透明度)
  
   //ジオメトリ
  let ballGeometry = new THREE.SphereGeometry(100, 64, 32); //球体のジオメトリの設定 
  
  //マテリアル
  let ballMaterial = new THREE.MeshPhysicalMaterial({
    color: 0x66ffff, // 青色を追加
    metalness: 0.4, // 金属度を低く設定
    roughness: 0.5, // 粗さを中程度に設定
  });
  
  //マテリアル
  let texture = new THREE.TextureLoader().load("./textures/Water.jpg"); //画像の読み込み
  let ballMaterial = new THREE.MeshPhysicalMaterial({
    map: texture, // 画像の指定
    color: 0x66ffff, // 青色を追加
    metalness: 0.4, // 金属度を低く設定
    roughness: 0.5, // 粗さを中程度に設定
  });
  
  //環境光の追加
  let ambientLight = new THREE.AmbientLight(0xffffff, 0.8);
  scene.add(ambientLight);
}
  

function animate() {
  // フレーム単位でアニメーションを読み込む
  requestAnimationFrame(animate);
  //レンダリングの記述
  renderer.render(scene, camera);
}

最後に

今回はGeometry・Material・Meshの概要とMeshの表示まで行いました。
様々なGeometry・Materialが用意されています。
気になる方は公式ドキュメントを見てみてください。
また、次回は光源について深堀りしていきます。
次回の成果物予定は下記です。