Blenderで作成した3Dモデルを、Three.jsでブラウザに表示する

# 概要

Blenderで作成した3Dモデルを、Three.jsの中に取り込み、ブラウザで表示できるようになるまでの手順を示します。

[Blender](https://www.blender.org/)は、3Dモデルを作成するのに適したソフトウェアです。
また、[Three.js](https://threejs.org/)は、ブラウザ上で動作する3Dモデルを作成するのに適した、JavaScriptのライブラリです。

なお、本記事では、どのようなフローでBlenderからThree.jsに3Dモデルを移行できるかを中心に記述します。そのため、Blenderでモデル作成、Three.jsの書き方についてはほとんど触れません。

# 手順
以下のような手順を実施していきます。

1. Blenderでモデルを作成する
1. 作成したモデルをglTF形式のファイルにエクスポートする
1. Three.jsにて、エクスポートしたglTFファイルをロードする

## Blenderでモデルを作成する

本記事ではモデルの作成方法の詳細ではなく、Blenderの情報をThree.jsに持っていく流れの方に焦点を当てます。  
そのため、ここではBlenderのサンプルサイトから取得してきたモデルを使いまわすことにします。

今回は[このページ](https://free3d.com/ja/3d-models/blender-%E5%BB%BA%E7%AF%89)から取得した無料3D建築モデルを利用していきます。

落としてきた圧縮ファイルを解凍すると、その中のどこかに`.blend`の拡張子のファイルがあるので、それをダブルクリックしてBlenderを開きます。
すると、以下のようなBlenderの画面があらわれます。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441085/6802309c-ae9c-a20e-5480-c08bc7d730b4.png)

これにてBlenderモデルを作成できた体とします。

## 作成したモデルをglTF形式のファイルにエクスポートする
画面から、
File → Export → glTF 2.0 (.glb/gltf)
をクリックし、任意の場所にglTFファイルをエクスポートします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441085/c199940d-21e4-00fa-aa72-abd34e44e9b8.png)

すると`～～～.glb`ファイルができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441085/6218d50f-8b2d-a9a7-eada-337edaede399.png)

※このファイルが本当にうまくエクスポートできているか不安な場合は、[glTF Viewer](https://gltf-viewer.donmccurdy.com/)に該当のglbファイルをドラッグアンドドロップして確認することができます。

## Three.jsにて、エクスポートしたglTFファイルをロードする

以下のようなフォルダ構成にします。(少し余計なものが入っているが、[このリポジトリのような感じ](https://github.com/nannany/threejs) )

```
threejs
│  building.glb
│  index.css
│  index.html
│      
└─js
    │  index.js
    │  
    └─threejs
            GLTFLoader.js
            OrbitControls.js
            three.min.js
```            

`building.glb`は、2番目の手順で作成したgltfファイルです。  
`index.css`は、ただのCSSファイルなので説明を割愛します。
`index.html`は、以下のようなコードとなります。

```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <link rel="stylesheet" href="index.css">
    <!-- three.jsを読み込む -->
    <script src="js/threejs/three.min.js"></script>
    <script src="js/threejs/GLTFLoader.js"></script>
    <script src="js/threejs/OrbitControls.js"></script>
    <!-- index.jsを読み込む -->
    <script src="js/index.js"></script>
</head>
<body>
<div id="main_canvas">
    <canvas id="canvas" width="100%" height="100%"></canvas>
</div>
</body>
</html>
```

配置したThree.jsライブラリを読み込んだり、canvas要素を配置したりしています。

`index.js`は、以下のようなコードになっています。

```js
window.addEventListener('DOMContentLoaded', init);

function init() {
    // レンダラーを作成
    const renderer = new THREE.WebGLRenderer({
        canvas: document.querySelector('#canvas')
    });
    // ウィンドウサイズ設定
    width = document.getElementById('main_canvas').getBoundingClientRect().width;
    height = document.getElementById('main_canvas').getBoundingClientRect().height;
    renderer.setPixelRatio(1);
    renderer.setSize(width, height);
    console.log(window.devicePixelRatio);
    console.log(width + ", " + height);

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

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

    const controls = new THREE.OrbitControls(camera, renderer.domElement);

    // Load GLTF or GLB
    const loader = new THREE.GLTFLoader();
    const url = 'http://localhost:8080/building.glb';

    let model = null;
    loader.load(
        url,
        function (gltf) {
            model = gltf.scene;
            // model.name = "model_with_cloth";
            model.scale.set(400.0, 400.0, 400.0);
            model.position.set(0, -400, 0);
            scene.add(gltf.scene);

            // model["test"] = 100;
        },
        function (error) {
            console.log('An error happened');
            console.log(error);
        }
    );
    renderer.gammaOutput = true;
    renderer.gammaFactor = 2.2;


    // 平行光源
    const light = new THREE.DirectionalLight(0xFFFFFF);
    light.intensity = 2; // 光の強さを倍に
    light.position.set(1, 1, 1);
    // シーンに追加
    scene.add(light);

    // 初回実行
    tick();

    function tick() {
        controls.update();

        if (model != null) {
            console.log(model);
        }
        renderer.render(scene, camera);
        requestAnimationFrame(tick);
    }
}
```

`building.glb`をロードしている部分は以下です。

```js
    // Load GLTF or GLB
    const loader = new THREE.GLTFLoader();
    const url = 'http://localhost:8080/building.glb';

    let model = null;
    loader.load(
        url,
        function (gltf) {
            model = gltf.scene;
            // model.name = "model_with_cloth";
            model.scale.set(400.0, 400.0, 400.0);
            model.position.set(0, -400, 0);
            scene.add(gltf.scene);

            // model["test"] = 100;
        },
        function (error) {
            console.log('An error happened');
            console.log(error);
        }
    );
```

`url`変数に格納している値が、gltfファイルのありかになっています。
threejsディレクトリ配下に格納している`GLTFLoader.js`、`OrbitControls.js`、`three.min.js`は、[Three.jsのGitHub](https://github.com/mrdoob/three.js/)からファイルをダウンロードして配置しています。
`GLTFLoader.js`は、3Dモデルのロードする役割を担います。
`OrbitControls.js`を使うことで、ブラウザでのマウス操作、キーボード操作等が可能になります。
`three.min.js`は、Three.jsのコアなライブラリです。

----

上記のファイル群が用意できたら、nodeの`http-server`コマンドを上記のthreejsディレクトリ直下で実行してください。

※`http-server`コマンドがインストールされていない場合は、下記コマンドを実行してインストールしてください。(nodeがない場合は https://nodejs.org/en/ からインストール)

```
npm install -g http-server
```

ブラウザから http://localhost:8080 にアクセスすると以下のような3Gモデルが表示されていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441085/6094d5d7-00af-7d7b-fb7a-310da706b23c.png)

また、ブラウザ上での操作は以下のようなことが可能です。

* 左右ボタンで左右水平方向にカメラの視点を移動させることができる
* 上下ボタンで画面の中心に向かってズームイン、ズームアウトすることができる
* 画面をクリックしながらマウスを操作することで、カメラの向き先をぐるぐる回すことができる

# 参考
https://threejs.org/docs/#manual/en/introduction/Loading-3D-models
https://codelabo.com/1192/
https://github.com/nannany/threejs