ダイキのアプリ開発ナレッジ

アプリ開発のナレッジを掲載します

Three.js 学習記録 基本的な使い方

はじめに

Three.jsの学習を記録していきます
Three.jsを使いこなしてゆくゆくは3次元的なサービスを提供できるフロントエンジニアを目指します

ビルドツールとThree.jsの導入

Viteを利用します
ja.vitejs.dev

自分はユーザー名に半角スペースを含むため、yarnではコマンドが失敗するためnpmでインストールします
ユーザー名の半角スペースでつまずく場合の参考:https://qiita.com/koseidaiki/items/d2be30379a7f05c37f62

 npm create vite@latest [プロジェクト名]

純粋なJSで開発する場合はvanilla
vueやreactで開発する場合はそちらを選択します
以下では純粋にJavaScriptで開発する方法で基本的な使い方を記載します

その後基本準備として

その後プロジェクトフォルダに移動して、

npm install three

package.jsonの内容をインストールする

npm install

Three.jsパッケージ使い方基本

JSで開発する場合にどうやって使うかですが、JSファイルに以下のモジュールをインポートして使います

import * as THREE from "three";

Three.js必要三要素と基本的な使い方

1. シーン 2. カメラ 3. レンダー

以下の3つの要素が必要であり、基本形は以下のようになる
1. シーン
2. カメラ
3. レンダー

main.js

import * as THREE from "three"; 

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({alpha: true}); // 背景を設定する場合は透過度を設定する
    renderer.setSize(window.innerWidth, window.innerHeight)
    document.body.appendChild(renderer.domElement);
    renderer.render(scene, camera);
} 

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ThreeJs</title>
</head>
<body>
    <script src="main.js" type="module"></script>
</body>
</html>

4 テクスチャ 5. ジオメトリ 6. マテリアル 7. メッシュ

上記では物体が表示されないので物体を配置したい場合はテクスチャ、ジオメトリ、マテリアル、メッシュを設定する
基本形は以下

main.js

    // テクスチャ = 柄 (https://threejs.org/docs/index.html?q=texture#api/en/loaders/TextureLoader)
    let textures = new THREE.TextureLoader().load("画像のPath")
    // ジオメトリ = 骨格 (https://threejs.org/docs/index.html?q=geometry#api/en/geometries/SphereGeometry)
    let ballGeometry = new THREE.SphereGeometry(100, 64, 32) // 例:球形
    // マテリアル = 材質 (https://threejs.org/docs/index.html?q=material#api/en/materials/MeshPhysicalMaterial)
    let ballMaterial = new THREE.MeshPhysicalMaterial({
        map: textures // テクスチャを設定
    }); 
    // メッシュ = ジオメトリ + マテリアル
    let ballMesh = new THREE.Mesh(ballGeometry, ballMaterial)
    scene.add(ballMesh) // 最後にシーンに追加する

    // 平行光源を設定することで物体を視認することができる
    let directionalLight = new THREE.DirectionalLight(0xffffff, 2);
    directionalLight.position.set(1,1,1)
    scene.add(directionalLight)  // 最後にシーンに追加する

8. アニメーション

また、基本的に動きのある画面を作りたいはずなので、アニメーションを使う
以下のようにアニメーション関数を作って、その中にレンダリングを入れて、変更のたびに再レンダリングをするような実装を行う


main.js

function animate() {
  // おまじない
	requestAnimationFrame( animate );
        // 動きのロジック - 例えばメッシュ(物体)の位置を変更するアニメーションをつけるなど
        // ballMesh.position.x += 時間に応じて加算
        // レンダラをこちらに入れる
	renderer.render( scene, camera );
}
// アニメーションを実行
animate();


ところで、これらにはバリエーションがありそのユースケースは以下のようになる

1. シーンについて

シーンについては基本的にバリエーションはなく思考停止で

scene = new THREE.Scene();

を使用すればよい
https://threejs.org/docs/index.html#api/en/scenes/Scene

2. カメラについて

カメラについては2つほどバリエーションがある
自分のアプリをどのように見せたいかを考えて適切なカメラを選択するとよい

1. PerspectiveCamera
遠近法(遠くのものは小さく)が適用される一番直観的な普通のカメラ
ユースケースは一番多いと思われる
https://threejs.org/docs/index.html#api/en/cameras/PerspectiveCamera


2. OrthographicCamera
遠近法が適用されないカメラ
遠くのものも近くのものも同じ大きさに見える
https://threejs.org/docs/index.html#api/en/cameras/OrthographicCamera

他にはStereoCameraがあって、立体的にみられるカメラもある模様
VRバイスが必須

2.1. カメラや物体のコントロールについて

カメラや物体のコントロール制御をできる簡便な機能がある

基本的には一番直観的なOrbitControlsを使っておけばよい
https://threejs.org/docs/index.html?q=Controls#examples/en/controls/OrbitControls

他一人称視点でコントロールしたいときは、FirstPersonControlsがある
https://threejs.org/docs/index.html?q=Controls#examples/en/controls/FirstPersonControls

2.2 光源について

Three.jsでは光源を必要とするマテリアル(MeshPhysicalMaterial)と必要としないマテリアル(MeshBasicMaterial、MeshNormalMaterial)があり、光源を必要とするマテリアルを使う場合に光源を設定する必要がある

光源にも種類があり、およそ4パターンほどある


1. 全体光源 AmbientLight
全方向から均一の光が当たる光源です
ちなみにThree.jsでは同じ物体の表裏の影はシミュレーションで表現されるが、他の物体に光がさえぎられても影ができることは基本的になかったり、他の物体から反射する光などはシミュレーションされていないので、物体の裏側の影の強さを表現することに使ったりすることができます
https://threejs.org/docs/index.html?q=Light#api/en/lights/AmbientLight


2. 平行光源 DirectionalLight
名が体を表している光源です
https://threejs.org/docs/index.html?q=Light#api/en/lights/DirectionalLight


3. 半球光源 HemisphereLight
2つの平行光源が互いに逆方向からやってくる光源です色を変えるなどができます
ユースケースは空と大地の対比を表現したいときに便利です
https://threejs.org/docs/index.html?q=Light#api/en/lights/HemisphereLight


4. 点光源 PointLight
とある1点から拡散する光源です
豆電球のイメージです
https://threejs.org/docs/index.html?q=Light#api/en/lights/PointLight


5. スポットライト光源 SpotLight
スポットライトや懐中電灯の光源のイメージです
https://threejs.org/docs/index.html?q=Light#api/en/lights/SpotLight


6. RectAreaLight
スタジオにおいてある四角形に広がる光源です
THREE デフォルトにないパッケージであることに注意が必要です
https://threejs.org/docs/index.html?q=Light#api/en/lights/RectAreaLight

3. レンダーについて

こちらもあまりバリエーションは考えなくていい
WebGLRendererを使う
https://threejs.org/docs/index.html#api/en/renderers/WebGLRenderer

4 テクスチャ

テクスチャーは画像を用意して物体に貼るというユースケースが最も多いと思われる
その場合は思考停止でTextureLoaderを使えばよい
https://threejs.org/docs/index.html?q=texture#api/en/loaders/TextureLoader

5. ジオメトリ

ジオメトリがそもそも何なのかというと物体の表面の任意の頂点を結んだ格子上の骨格のことです
不規則な形をとる物体の場合、任意の頂点の数が多ければ多いほど再現度が高くなります
フラーレンのイメージです

ジオメトリは種類が多く、こちらから使いたい出来合いのジオメトリを使うことが便利です
https://threejs.org/docs/index.html?q=geometry

よく使うものとしてはBoxGeometry, PlaneGeometry, SphereGeometry, TorusGeometry あたりだと思います
任意の形を自作する場合はBufferGeometryのベーシッククラスを継承して作成するか他の3Dソフトで作成したものをインポートする必要がある

6. マテリアル

マテリアルは物体の材質に相当するものです
大きく分けて光源を必要とするものと光源を必要としないものに分かれます
光源を必要としないものはMeshBasicMaterialとMeshNormalMaterialがあります
光源を必要とするものにはMeshPhysicalMaterialがあります
他のパラメータとしては金属光沢や粗さ、色などがあります
パラメータが多くデザインの範囲なのでUIデバッグをつけると便利です
https://threejs.org/docs/index.html?q=material

7. メッシュ

フラーレンに皮をつければサッカーボールになるイメージです
メッシュも基本的には組み立て作業に相当するためバリエーションは特にありません
思考停止でMeshオブジェクトを生成します
これが物体に相当します
注意点としてはこれを作った後にシーンに追加することを忘れないようにします

const box = new THREE.Mesh(
  new THREE.BoxGeometry(1,1,1), 
  new THREE.MeshNormalMaterial()
)
scene.add(box) // これを忘れない

UIデバッグ

UIデバッグというのはわざわざコードに戻らなくても画面上でパラメータの変更ができる機能のことです
この機能を使うと画面右上にパラメータをいじれるUIが出てくる

lil-guiを使用する
インストール方法は下記
lil-gui.georgealways.com

インスタンスを生成して、パラメータを追加するとすぐに利用できる(CDNを利用)
sceneにメッシュを追加するのと同じ要領

import GUI from 'https://cdn.jsdelivr.net/npm/lil-gui@0.16/+esm';
const gui = new GUI()

// boxというオブジェクトを作成

gui.add(box.position, "x") // x軸に沿って動かせるようになる
gui.add(box.position, "x", -3, 3, 0.01) // ドラッグで動かせるようになる
gui.add(box.position, "x").min(-3).max(3).step(0.01) // こういう書き方もできる

.nameを使用すると名前を付けることができる

THREE デフォルトにないパッケージを使う

THREE デフォルトにないパッケージを使う場合、jsmフォルダ内にある可能性がある
フォルダパス自体は以下
three.js-r[VERSION]\three.js-r[VERSION]\examples\jsm

光源のhelpers関数などがこちらに入っている場合がある

おわりに

今後は本格的なフロントエンド開発を行っていきたいので、Vue.jsにおけるThree.jsの使い方を調査していこうとおもいます

[追記]
残念ながらVue.js3.0でThree.js開発を行うことは現実的ではない様子
Three.jsをそのまま使う場合、Vueの書き方との相違が多くかなり使いずらいことが分かっている
そのためVueGLというライブラリが用意されているが、それもVue3.0系にはまだ対応しておらず、実質VueでのThree.js開発はあきらめた方が良いことが分かった
最近のフロントエンドはほぼReactによってきつつあるようにも見えるので、まだフロントエンドのどのフレームワークにも染まっていない人はReactを選んでおけば間違いがない気がします(Vue3.0簡単とか言ってるやつ、あれは詐欺です。Vueは書き方がありすぎてもはやブログなどで検索して出てきた情報が全くアテにならなかったりするので、ぶっちゃけ初心者には難しいです。Vueのドキュメントで読んで理解が進められる人はReactでも同じではと思ったりします。サポートされているライブラリもReactの方が多い印象ですし。)