CrossRoad

XRを中心とした技術ブログ。 Check also "English" category.

ES6以降の仕様でthreejsのコードを記述する方法について

前回、Babylon.jsをES6以降の仕様で書く方法をまとめました。

www.crossroad-tech.com

引き続きES6に慣れるため、Babylon.jsと似ているthree.jsについても書き方を調べてみました。ただ、three.jsを初めて使ったためか、うまく動かず情報を探すことができなかったため、今回整理した内容をまとめてみました。

使用したthree.jsのバージョン (npm package ) : 0.116.1

1. ES6でthree.jsのコードを書く手順

今回のソースコードは以下のリポジトリにまとめました。

GitHub - flushpot1125/threejs-es6

1.1 フォルダ作成、npm init

まずはソースコードを格納するためのフォルダを作り、npmコマンドを実行します。

$ npm init --y

このコマンドは前回の記事と同様です。

1.2 webpackでビルド、サーバ環境を構築する

webpackは、複数のjavascriptファイルをまとめて1つにする仕組みです。また、webpack-dev-serverを使うことで、簡易的なWebサーバをすぐに作ることができます。

$ npm install webpack webpack-cli webpack-dev-server --save-dev

インストール後、webpack.config.jsを作って設定内容を書きます。

gist.github.com

書き方は前回同様、以下の記事を参考にさせていただいています。

qiita.com

この設定ファイルにより、自分で書いたソースコード (src/index.js)を起点として、1つにまとまった.jsファイル (app.js) がindex.htmlと同じ場所に生成されます。

1.3 three.jsのモジュールをインストールして最低限のコードを書く

インストールする手順はこれだけです。

$ npm install three

今回は、webpack.config.jsの記述に沿って、src/index.jsとindex.htmlを作ります。このindex.jsにthree.jsのコードを書きます。

gist.github.com

gist.github.com

app.jsは実体としては存在せず、webpackによってサーバ起動時に動的に生成されます。ターミナルから npm start を実施して、http://localhost:4000 にアクセスすると、このように表示されます。

minimum three.js sample

1.4 .obj、.mtl、テクスチャを読み込んで表示させる処理を追加してみる

先ほどまでで最低限の環境構築はできています。ただ、この後.objファイルを読み込む処理を追加したところ、思ったよりも詰まったので.obj、.mtl、テクスチャファイルを読み込んで表示させる方法を追記しておきます。

このようなコードを書きます。index.htmlは変更なしです。

gist.github.com

また、コードに書いたディレクトリ構成に沿って、assets/importobjtest/に.obj、.mtl、テクスチャファイルをおきます。

ターミナルから npm start を実施して、http://localhost:4000 にアクセスすると、このように表示されます。

Show obj model on three.js

2. three.jsで書くときのtips一覧

2.1 three.jsのモジュールの多くは、examples/jsmフォルダ以下を指定する

Importable Examples
The core of three.js is focused on the most important components of a 3D engine. Many other components like loaders or controls are part of the examples directory. three.js ensures that these files are kept in sync with the core but users have to import them separately if they are required for a project. You can find in the examples/jsm directory an ES6 module version for almost all example files. If you install three.js via npm, you can import them like so:

引用元:Import via modules - three.js

ここに書かれている通り、コアな処理はTHREEを宣言しています。

import * as THREE from 'three';

そのため、 new THREE.Scene() のように、THREEをつけることで使えます。しかし、THREEで宣言しても出てこない場合があります。たとえば、.objファイルを読み込むためのOBJLoaderをTHREE.OBJLoaderとするとエラーが出ます。

Uncaught TypeError: three__WEBPACK_IMPORTED_MODULE_0__.OBJLoader is not a constructor  at init (index.js:47)

正しくは.jsまで指定してこのように書きます。

import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';

2.2 importを使うときは、名称を{}でくくる

以下のように書くとエラーが出ます。

//間違い
import  OBJLoader  from 'three/examples/jsm/loaders/OBJLoader.js';
ncaught TypeError: three_examples_jsm_loaders_OBJLoader_js__WEBPACK_IMPORTED_MODULE_3__.default is not a constructor
    at init (index.js:47)

あるいはこのようなエラーが出ることもあります。

./src/index.js 47:24-33
"export 'default' (imported as 'OBJLoader') was not found in 'three/examples/jsm/loaders/OBJLoader.js'

念のためですが、正しい書き方は下記です。

import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';

私の場合、Visual Studio Codeの文法チェックではエラーが出なかったのでしばらく気づけませんでした。

2.3 objモデルの読み込みエラーが出ていないのに3Dモデルが表示されない

カメラの位置が3Dモデルから離れている可能性があります。たとえば、three.js Editorを使ってモデルを表示してみると、3Dモデルに設定された位置がわかります。

An example view of three.js editor

ここで、カメラの位置より大幅にずれている、あるいはモデルが大きすぎる、小さすぎるなどがわかるので、その場合はモデルを修正するか、three.jsのコード側(たとえばカメラの位置やfovの値)を変更することで対応できます。

なお、three.js Editorは、以下よりアクセスできるWebベースのGUIエディタです。

three.js / editor

2.4 マウス操作用のOrbitControlを使うと、OrbitControls.js:1110 Uncaught TypeError: Cannot read property 'addEventListener' of undefinedが出る

このように書くとエラーになります。

let controls = new OrbitControls(camera);

これは、three.jsのあるバージョン(どこからかは調べきれてません)から、マウスコントロール対象のcanvasも指定することになったためです。

正しくはこう書きます。

gist.github.com

以下のようにcanvasを指定しても動きます。

gist.github.com

なお、マウス操作につかえるTrackballControlsを使うときも、第2引数にcanvasの情報(書き方は上記どちらでも良さそう)が必要です。
これを書かないと、同じようにエラーが出ます。

Uncaught TypeError: Cannot read property 'addEventListener' of undefined
    at new TrackballControls (app.js:61073)
    at init (app.js:64293)

3. おわりに

今回調べてわかったのですが、three.jsはバージョンによって変更が激しいようです。そのため、Web上に多数の情報があるのですが、その通りに書いても動かないことがありました。

既知の方には基本的な話が多いのですが、これからWebXR関係のアプリ開発を始める方の参考になれば幸いです。