Blenderで3D表現を試みる

## はじめに
こんにちは。
オークファン開発部デザイナーの@af_etoです。

Adobe Creative Cloudの通知で、Substance 3Dに触れたきっかけで、
3DCG制作に取り組んでみることにしました。

基礎的な3DCG制作を習得しておけば、
簡単なものは少しの手間で作れて便利かもしれません。
デザインの選択肢が増えるならば、表現の幅も広がるかも!?

## シンプルなイメージ画像を作ってみる
架空のコーポレートサイトのデザインを元に考えようと思います。

例えば、下の画像のようなページの余白（薄いグレー部）に、
ロゴマークが3Dになったものをさり気なく敷いて、
少し工夫したコーポレートアイデンティティみを出してみたいと思います。

![jizn_corp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/1e24dbe4-248d-c0f9-27a6-10a0e7b42b24.png)

ロゴマークをぼんやり設置してみてもいいですね。

![jizn_corp_easy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/d752f25c-d380-ac59-327b-5502482b0441.png)

ニューモーフィズム感出してみたり。
背景画像だけで印象が大きく変わりますね。

![jizn_corp_neumorphism.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/57be6e79-ef4d-b93a-1b0e-ed4e7fd8ee7c.png)

これで雰囲気は充分な気もしますが、
試しに3Dロゴマーク画像を作成して設置してみましょう。

### Blenderを利用する
どうやらAdobeのSubstance3Dは有料らしいので...、
無料で使えるオープンソースの3DCGソフト『Blender』を使います。
まずはダウンロード＆インストールします。

https://www.blender.org/download/

#### Blenderの初期設定
Blenderを起動すると立方体が置いてあり、よく見るとカメラと照明っぽいものもあります。
初期設定として配置されているようです。
英語表示になっているので、上部メニューの`Edit > Preference`から`Interface > language`を「日本語」に変更します。

![Blender初期表示.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/e4d2c69c-198a-b265-cf34-855181489235.png)

マウスホイールを回したり、マウスホイールの中心を押して画面をグリグリすると、視点が動きます。
操作は環境によって違いがあるかもしれません。

画面右上の「XYZ」を押すと視点がそれぞれの軸に移動し、テンキーでも視点を変えられるようです。
使い方が分からな過ぎて、しばらく適当に触ってましたが、
XYZという方向感覚をまず身に付けると、操作がスムーズになりそうです。

![Blender初期表示Z.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/44c9ef57-0f29-5679-dd44-87dd8faaa810.png)

「Z」真上からの視点です。
カメラと照明の位置関係もわかります。

#### 初期設定でのレンダリング
この初期状態で、カメラに写っている映像をプレビューしてみましょう。
上部メニューの`レンダー > 画像をレンダリング`してみると、

![Blender初期レンダリング.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/30d871a4-9e2a-5316-ec80-e9d2ee0c055c.png)

およそ想像通りの画像が表示されました。
「物体を作成し、カット・構図を決めてライティング、カメラで撮る」のような手順で進めればよさそうですね。

#### SVGデータの読み込み
SVGデータを読み込めるようなので、複雑なロゴマークも簡単に立体化できそうです。
上部メニューの`ファイル > インポート`で読み込むSVGファイルを選択すると、

![SVG読み込み.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/39f1d6d2-399a-2830-cc01-a04a3faf6cea.png)

ペラっと配置されます。
それを右の操作パネル`オブジェクトプロパティ`でX軸で90度回転させて起こします。

![SVG回転X.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/fe130f24-eb0f-2e96-0f43-acb8c712bac2.png)

さらに`tab`キーで`編集モード`に変更して、`面`を選択して押し出します。

![SVG押出しと色.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/8ed9b4b4-6116-99cc-8af8-bea58de1a0d6.png)

立体ロゴマークができました！
さらにSVGから引き継がれた黒は不要なので、
右操作パネル`マテリアルプロパティ`から「SVGMat」を削除して、ベースカラーを白にしました。

>`tab`キーで`編集モード`に変更して、`面`を選択して

と、ざっくり書きましたが、
`オブジェクトモード`ではオブジェクトそのものを選択でき、`編集モード`ではオブジェクトの`頂点、辺、面`を選択することができます。
オブジェクトを選択して`tab`キーを押すか、左上のモード設定のセレクトボックスで切り替えが可能です。

ロゴマークの立体化にあたっては、ロゴマークを`編集モード`にして`面`を選択、
右クリックメニューの`面を押出し`で立体化しました。

#### 背景を設置する
立体ロゴの影を落として、さらに立体感出したいので、背景を置いてみます。
`Shift+A`を押すと新規でオブジェクト、カメラや照明を設置することができます。
`メッシュ > 平面`を追加して、角度や位置を調整します。

![SVGに背景設置.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/579ff35a-c31e-4cee-d4cd-9c8895786383.png)

さらに、照明を正面斜めから照らして、カメラも反対の正面斜めから構えます。
下の図はそのセッティングを真上から見たものになります。

![何となくセッティング.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/b20179e0-0029-4997-bbe8-fec5398b70e0.png)

そこでレンダリングしてみます。

![何となくレンダリング.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/48bf9628-b53d-4105-8445-d0a7f4f5340c.png)

立体ロゴにフォーカスしてませんでした。背景の切れ目も見えてしまってます。
少し上から捉え過ぎているかもしれません。

#### 再セッティング
初期設定のカメラの調整が難しかったので、
`Shift+A`で正面に向けた新規カメラを追加します。
水平を保ちながら、角度を変えて、

![新規カメラ配置.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/b84bcec1-cf91-1243-ff0c-5b93267851e2.png)

背景も切れないようにサイズを変更してレンダリングすると、

![新規カメラ配置レンダリング.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/d024a260-0196-2cbb-ef96-d8c244fc76f1.png)

ちょっといい感じになりました。
立体ロゴと背景をもう少し近づけて、もっと明るくして..といった具合に、
自分のイメージに近づくようカメラや照明を調整していきます。

![照明調節.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/3648bd5a-1bf5-a171-12c0-91ba5478b326.png)

照明を強めで、カメラは少し遠目から狙って、

![カメラ調節.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/f9fa8207-b0f9-fc30-5d0c-e5aeb7fabc51.png)

画角も調整して、

![レンダーエンジン変更.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/94e6cb96-89ba-2316-2fcb-dff9b78d582f.png)

レンダリングすると、

![それっぽくなった.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/d8bca431-4ec7-457c-985a-fd70b01c6122.png)

なんとか背景画像に使えるかもしれない。
細部の追求は後にして、ひとまずこれで完成とします。
レンダリング画像のウィンドウの上部メニュー`画像 > 名前を付けて保存`し、
明るさ、コントラストを調整して、先程のページタイトル背景に敷いてみます。

### 背景画像の完成
![jizn_corp_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/78e0420d-27ac-4de8-1c42-9c87932c6bf9.png)

うーん...。はじめてなので、これで良しとしましょう！

## 3DデータをWEBページで動かす
「Blender」でGoogle検索していると、three.jsを使って
3DデータをWEBページに表示する記事を多く見かけます。
頑張ればできそうなのでやってみましょう。

### 動作を決める
再び架空のサービスサイトのデザインを元に考えようと思います。

下の画像のようなページ構成のスマートフォンを3Dデータにして、
マウスの動きに合わせてユラユラ動かしてみます。

![jizn_static.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/91282a04-81fb-efb4-b121-475d88088420.png)

### 2D画像から3Dモデルを作成する
Blenderでスマートフォンを作成するのですが、
まずはガイドとなるスマートフォンを2Dで作成し、Blenderに読み込みます。

![2D画像読み込み.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/bbc12e4b-c6a7-a7ec-3ae4-2e1ec8f787b7.png)

`Shift+A`で`メッシュ > 立方体`を追加して、形状を合わせていきます。
角に丸みを付けたい場合は`編集モード >　辺`で丸みをつけたい辺を選択し、`control+B`で角を取れます。

![角をとる.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/be95cd26-9b6d-7a6f-b915-c8a4406d2c28.png)

`押し出し`でスピーカー部のへこみを作ります。

![スピーカー部押し出し.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/a6b04e16-d1a5-26a9-011e-4b1e7ca471eb.png)

ボタンを取り付けて、

![ボタン取り付け.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/367dca5e-3889-1442-2068-3a55adc32e1f.png)

色をつけて、

![色をつける.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/0bd74e0a-b73e-1b95-4a6d-26be0f07be0b.png)

ページのキャプチャをスクリーン画面に設定します。

![スクリーン貼り付け.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/6be5168e-c2dc-12aa-d3af-c50ed400f1ff.png)

工程の詳細をだいぶ省略してますが、操作にさえ慣れれば、割と手軽に作れます。

![セッティング.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/274d0c04-b959-632d-e27f-855dabc04de0.png)

カメラや照明を調整してる風ですが、かなり暗中模索です...。
やればやるほど遠ざかっていくような気がしているので、
きちんと基礎から学習しなければならないなと痛感しています。

![何となく完成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/05232cdc-296c-f165-085a-d23c7a39176d.png)

ひとまずスマートフォンの3Dデータは完成しました。

上部メニューの`ファイル > エクスポート > glTF 2.0 (.glb/gltf)`から
3Dデータを「glTFファイル」の形式でエクスポートして準備完了です。

#### three.jsのダウンロード
Github、または公式からThree.jsのライブラリ一式をダウンロードします。

https://threejs.org/

https://github.com/mrdoob/three.js/

#### three.jsのライブラリを読み込む
必要なjsファイルを任意のフォルダにコピーします。
```html:index.html
<script src="/assets/js/threejs/three.min.js"></script>
<script src="/assets/js/threejs/OrbitControls.js"></script><!-- カメラ制御 -->
<script src="/assets/js/threejs/RoomEnvironment.js"></script><!-- 環境光制御 -->
<script src="/assets/js/threejs/GLTFLoader.js"></script><!-- glTFの読み込み -->
<script src="/assets/js/index.js"></script>
```

#### HTML
描画エリアとなるcanvas要素を用意します。
```html:index.html
<div id="canvasBox"><canvas id="canvas"></canvas></div>
```

#### 3D表示用のJavaScriptを用意
##### レンダラー作成（画面描画）
```javascript
const renderer = new THREE.WebGLRenderer({
    // 出力するcanvas要素
    canvas: document.querySelector('#canvas')
});
```

##### canvas設定
```javascript
// canvas親要素
const container = document.getElementById('canvasBox');
// ウィンドウサイズ設定
let windowW = window.innerWidth;
let windowH = window.innerHeight;
// canvasサイズ設定
let parentW = container.clientWidth;
let parentH = container.clientHeight;
```

##### レンダラー設定
```javascript
// 描画サイズ調整
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(parentW, parentH);
// 背景透過
renderer.setClearColor(0x000000, 0);
// Blenderの色をThree.jsで再現する設定
renderer.physicallyCorrectLights = true;
renderer.outputEncoding = THREE.sRGBEncoding;
// シャドウ有効
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
```

##### シーン作成
```javascript
const pmremGenerator = new THREE.PMREMGenerator(renderer);
const scene = new THREE.Scene();
```

##### 環境光設定
```javascript
const roomEnviroment = new THREE.RoomEnvironment();
scene.environment = pmremGenerator.fromScene(roomEnviroment, 0.04).texture;
```

##### glTF/glbロード
```javascript
// カメラを作成
let camera;
const loader = new THREE.GLTFLoader();
// glTFファイル
const url = 'assets/glb/smartphone.glb';

let model = null;
loader.load(
    url,
    function (gltf) {
        model = gltf.scene;
        // シーンにモデル追加
        scene.add(model);
        // Blenderで作成したカメラの配列
        camera = gltf.cameras[0];
        render();
    },
    undefined, function (e) {
        console.log(e);
    }
);
```

##### マウス座標管理用のベクトル
```javascript
const mouse = new THREE.Vector2();
const windowHalf = new THREE.Vector2(
    windowW / 2,
    windowH / 2
);
```

##### マウスイベント
```javascript
function onDocumentMouseMove( event ) {
    mouse.x = (event.clientX - windowHalf.x) / windowHalf.x;
    mouse.y = (event.clientY - windowHalf.y) / windowHalf.y;
    scene.traverse(function(obj) {
        if (obj.isMesh) {
            obj.rotation.y = mouse.x / 2;
            obj.rotation.x = mouse.y / 2;
        }
    });
}
```

##### レンダリング
```javascript
function render() {
    requestAnimationFrame(render);
    renderer.render(scene, camera);
}
```

### ブラウザで確認
何とか動きました。。。
ひとまず、マウスの動きに合わせて3Dデータが動いているので良しとしましょう。
https://manahub.github.io/jizn/

![完成.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301766/366906ad-b8a1-4bd3-834b-370347a59b2b.gif)

## おわりに
スマートフォンの3Dモデル作成の際に、照明設定が上手にできず、Blenderの照明は利用しませんでした。
やはり、マテリアル、照明、カメラの設定を基礎から学習する必要がありそうです。
そのうち3D動画制作もやってみたいと思います。

### 参考記事
* [【Blender×three.js】Webブラウザ上でモデルとアニメーションを再現する](https://morymory.com/2022/04/11/%E3%80%90blenderxthree-js%E3%80%91web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E4%B8%8A%E3%81%A7%E3%83%A2%E3%83%87%E3%83%AB%E3%81%A8%E3%82%A2%E3%83%8B%E3%83%A1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3/)
* [three.jsでBlenderのカメラを使う](https://qiita.com/xrxoxcxox/items/cc7662fcf51182cc161c)
* [Blenderで作成した3Dモデルを、Three.jsで表示した際の「色味が違う…」の解決方法](https://liginc.co.jp/576599)
* [【Three.js】Blenderで作った3Dモデルを動かす](https://blog.design-nkt.com/osyare-threejs28/)