🐶

Three.jsチートシート

2022/12/24に公開

JavaScript Advent Calendar 2022 24日目の記事です。

Three.jsを軽く試したい時に、毎度調べたり思い出すのが大変なので個人的にまとまっていたら嬉しいという情報をまとめてみました。

Three.jsでとりあえず、何かを表示

index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8"/>
  <script src="https://unpkg.com/three@0.147.0/build/three.min.js"></script>
  <script>
    const init = () => {
      const width = window.innerWidth;
      const height = window.innerHeight;
      const canvas = document.getElementById('canvas');
      const renderer = new THREE.WebGLRenderer({
        canvas,
      });
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(width, height);
      const scene = new THREE.Scene();
      const camera = new THREE.PerspectiveCamera(45, width / height);
      camera.position.set(1000, 1000, 1000);
      camera.lookAt(0, 0, 0);
      const light = new THREE.DirectionalLight(0xffffff, 1);
      scene.add(light);
      const geometry = new THREE.TorusGeometry(200, 100, 64, 100);
      const material = new THREE.MeshLambertMaterial({color: 0xee6666});
      const mesh = new THREE.Mesh(geometry, material);
      scene.add(mesh);
      const tick = () => {
        renderer.render(scene, camera);
        requestAnimationFrame(tick);
      }
      tick();
    }
    window.addEventListener('DOMContentLoaded', init);
  </script>
</head>
<body>
  <canvas id="canvas"></canvas>
</body>
</html>

このhtmlをブラウザで開けると、とりあえず表示はできます。
torus

補足

unpkg

NPMに登録されているパッケージをCDNで呼び出せるサービスです。

モジュール版

公式ではモジュール版の読み込みサンプルで説明していますが、とりあえず表示するだけならこれでOKです。
https://threejs.org/docs/#manual/en/introduction/Installation

ただし、以下のサイトによると、exapmple/jsが廃止される?ようで、
https://discourse.threejs.org/t/the-examples-js-directory-will-be-removed-with-r148/45349

<script src="https://unpkg.com/three@0.147.0/build/three.min.js"></script>

の記述を足すだけではversion148以降は表示できなくなる可能性があります。
その場合は

<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
<script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/three@0.147.0/build/three.module.js"
    }
  }
</script>
<script type="module">
  import * as THREE from 'three';
  // ここに書いていく
</script>

と書き換えてください。

バージョン

CDNで読み込むバージョンは下記URLで最新を都度確認すると良いでしょう。
https://unpkg.com/browse/three@0.147.0/

パッケージマネージャでインストール

npm install three

公式ではnpmの例を書いていますが、yarnでも大丈夫です。

yarn add three

型定義ファイルの導入

npm install --save-dev @types/three
# もしくは
yarn add --dev @types/three

ちなみに、型定義ファイルは以前同梱されていましたが、今はDefinitelyTypedに移されています。
https://discourse.threejs.org/t/with-r126-typescript-type-declaration-files-are-located-at-definitelytyped/23157

インタラクティブにオブジェクトを操作

マウスやタッチ操作でカメラを動かしたい場合はOrbitControlsを用いることが一番手軽で定番です。
Three.jsでとりあえず、何かを表示のindex.htmlにOribitControlsを読み込み、インスタンス化すればマウスやタッチでオブジェクトを動かすことができます。

index.html
<script src="https://unpkg.com/three@0.147.0/examples/js/controls/OrbitControls.js"></script>
index.html
const controls = new THREE.OrbitControls(camera, canvas);

モジュールでの読み込みの場合は以下に読み変えてください

index.html
  <script type="importmap">
    {
      "imports": {
        "three": "https://unpkg.com/three@0.147.0/build/three.module.js",
        "three/addons/": "https://unpkg.com/three@0.147.0/examples/jsm/"
      }
    }
  </script>
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
new OrbitControls(camera, canvas);

補足

Three.jsのコアな機能以外はexamplesディレクトリ以下にあります。
インタラクティブに操作できるようにするアドオンは他にも用意されているので、用途が合わない場合は以下のURLを確認してもいいかもしれません。
https://threejs.org/docs/index.html?q=controls

外部のオブジェクトを読み込んで表示

// 以下のパスは適宜読み換えてください
// 1
import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';

// 2
const loader = new OBJLoader();
//3
loader.load('./xxx.obj', (obj) => {
  // 4
  scene.add(obj);
});

手順を軽く説明すると、
1.OBJLoaderをimpot
2.インスタンス化
3.loadの引数にパスを指定して読み込み
4.コールバック関数内でobjをsceneに追加
です。

補足

Three.jsでとりあえず、何かを表示のindex.htmlにのソースコードに追加しても動きません。
CORSの設定でブラウザエラーが起こるはずです。
範囲を超えるので説明しませんが、ブラウザの設定を変更したり、WEBサーバーを用意する必要があります。

とにかくアニメーションさせたい

const tick = () => {
 mesh.rotation.x += 0.01;
 mesh.rotation.y += 0.01;
 renderer.render(scene, camera);
 requestAnimationFrame(tick);
}
tick();

かなりシンプルな例になりますが、meshをフレームごとに回転させるにはこのようにすれば大丈夫です。

カメラの向きの変更

camera.lookAt(0, 0, 0);

lookAtメソッドに任意の座標を引数に与えるとカメラの向きが変わります。
OribtControlsなどを使用していると競合して動かない場合があるので注意してください。

平行投影のカメラを使用

const camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, -1000, 1000 );

OrthographicCameraを使うことで、遠近感のないカメラに変更することができます。

直方体を追加

const geometry = new THREE.BoxGeometry( 500, 500, 100 )
const material = new THREE.MeshLambertMaterial({color: 0xee6666});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

他にもいろいろな形がThree.jsには用意されているので、以下で色々探して遊んでみてもいいと思います。 
https://threejs.org/docs/?q=geometry

オブジェクトの色を変更

const material = new THREE.MeshLambertMaterial({color: 0xee6666});

マテリアルの引数のカラーコードを変更すればOK。
よくサンプルコードで使用する下記のようなMeshBasicMaterialも引数を変更すればOK。

const material = new THREE.MeshBasicMaterial( {color: 0xee9900} );

リサイズ時にサイズを調整したい

<meta name="viewport" content="width=device-width, initial-scale=1"/>

htmlにレスポンシブ対応でお馴染みのおまじないを追加します。

const resizeHandler = () => {
  const width = window.innerWidth;
  const height = window.innerHeight;
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(width, height);
  camera.aspect = width / height;
  camera.updateProjectionMatrix();
}
window.addEventListener('resize', resizeHandler);

このコードをinitの中に書けばリサイズ時に調整されるようになります。
パフォーマンスや保守性を考慮したコードになっていませんが悪しからず。

テクスチャを設定

const texture = new THREE.TextureLoader().load(path);
const material = new THREE.MeshStandardMaterial({
  map: texture
});

pathは任意の画像パスを設定してください。
これもまた、loaderを使用するのでCORSの制限に引っかかる可能性があるのでご注意ください。

参考

https://threejs.org/
https://ics.media/tutorial-three/

Discussion