44
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

WebグラフィックスAdvent Calendar 2021

Day 3

Blenderで3Dモデルを作成し、webpack × Three.js でサイトを作成する

Last updated at Posted at 2021-12-02

##概要
今回はQiitaのキャラクター(Qiitan)の3Dモデルを作成し、Three.jsで表示するサイト作成まで書いていこうと思います。
長くなってしまいますが、参考になるところがあれば嬉しいです。

##対象
・ Blenderをやってみたい人
・ Three.jsを使って3Dモデルのサイトを作ってみたい人
・ webpackを使った開発環境がある人(※webpackの細かい説明は省略しているため)

##目次

  1. バージョンなど
  2. Blenderのダウンロード
  3. よく使うショートカット
  4. BlenderでQiitanを作成
  5. ファイル構成
  6. Three.jsでglbファイルを読み込む
  7. GSAPでアニメーションをつける
  8. 完成
  9. 参考

##1. バージョンなど
macOS Big Sur v11.4
Blender v2.93.1
Node v16.4.2
vscode v1.60.0
webpack v5.27.2
typescript v4.2.3
three.js v0.133.1
gsap v3.8.0

##2. Blenderのダウンロード
こちらからダウンロードできます。
https://www.blender.org/download/

##3. よく使うショートカット
3D制作で非常に使えるショートカットを紹介します。
ショートカットを覚えると大幅な時間短縮ができます。

オブジェクトモード、編集モード共通

Aキー
→オブジェクトの全選択

Xキー
→削除

Tabキー
→オブジェクトモードと編集モードを切り替える

Gキー
→対象を移動できる
 →Gキー + x(y,z)でX(y,z)軸に方向にのみ移動させる

Rキー
→対象を回転できる
 →Rキー + x(y,z)でx(y,z)軸に方向にのみ回転させる

Sキー
→対象の拡大、縮小ができる

Shift + Aキー
→球体や立方体、平面などを生成する

Shift + Dキー
→対象物の複製

編集モードのみ

Eキー
→対象の頂点、辺、面を押し出す

Fキー
→対象に面を張る

Alt(option)+ 左クリック
→周を選択

頂点、辺、面を選択した状態で Ctrl(command) + r
→オブジェクトにぐるっと一周辺を入れることができる(ループカット)

##4. BlenderでQiitanを作成
早速作成していきます。
今回作成するQiitanの画像は下記のサイトからお借りしました。
https://suzuri.jp/qiita

こちらを参考に作成します。
スクリーンショット 2021-11-14 11.58.11.png

デフォルトで設置されているカメラ、メッシュ、ライトを削除します。
__Aキー__で全選択し、__Xキー__で削除を選択。
スクリーンショット 2021-11-12 13.40.00.png

右上のナビゲートで__-Y(画像赤四角)__をクリックし、作業画面を設定します。
__Shift + Aキー__で__画像__から__背景__を選択。
az.png

Qiitanの画像を追加します。
スクリーンショット 2021-11-12 13.42.29.png

__Shift + Aキー__で__メッシュ__から__UV球__を選択。
スクリーンショット 2021-11-12 13.43.24.png

UV球を選択した状態で__Tabキー__で編集モードにします。
右上の__オブジェクトの透明化(画像赤四角)__を有効にして、先程追加した背景画像を見られるようにします。
aw.png

UV球を選択した状態で、__Sキー__でUV球をQiitanの全体サイズに合わせます。
スクリーンショット 2021-11-12 13.44.57.png

左側半分を選択し、__Xキー__で__頂点__を削除します。
スクリーンショット 2021-11-12 14.30.26.png

右側全体を選択し、__モディファイアの追加__から__ミラー__を選択。
スクリーンショット 2021-11-12 14.30.59.png

__クリッピング__にチェックを入れます。
これで簡単に左右対称のモデルが作成できるようになります。
スクリーンショット 2021-11-12 14.31.13.png

上部真ん中にある__プロポーショナル編集(画像赤四角)__を有効にして、耳を作成します。
(この時右側だけ動かせば自動的に左側も同じように動きます。)
aq (1).png

耳を丸くしたいので、__Ctrl + Bキー__でベベルをします。
幅1m、__セグメントは5__とします。
スクリーンショット 2021-11-13 10.29.41.png

増やした頂点を背景画像に合わせて__Gキー__で移動します。
スクリーンショット 2021-11-13 10.30.25.png

同じ要領で体全体も背景画像に合わせます。
スクリーンショット 2021-11-13 10.31.50.png

ここまでできたらミラーを終了します。
__Tabキー__でオブジェクトモードに変更し、__ミラーの「∨」__から__適用__を選択。
次に尻尾を作っていきます。
スクリーンショット 2021-11-13 10.37.00.png

__3キー(または左上の赤四角をクリック)__で面選択モードに変更。
右後ろの4面を選択します。
aa.png

__Iキー__で面を差し込みます。
スクリーンショット 2021-11-13 10.40.25.png

そのまま__Gキー__で面を押し出します。
スクリーンショット 2021-11-13 10.40.46.png

右上のナビゲートで__-Y__をクリックし、作業画面を設定。
尻尾に合わせて__Gキー__で頂点を移動していきます。
(1キー、または赤四角をクリックで頂点選択モードに変更できます。) 
ok.png

頂点が足りないときは__Ctrl + R__(ループカット)で頂点を増やします。
スクリーンショット 2021-11-13 10.46.03.png

尻尾はこんな感じで完成です。
スクリーンショット 2021-11-14 9.55.50.png

__Tabキー__でオブジェクトモードに変更。
__Shift + A__で__メッシュ__から__円__を追加します。
スクリーンショット 2021-11-14 10.00.51.png

X軸方向に90度回転するために
RキーXキー、__90__の順で入力します。
スクリーンショット 2021-11-14 10.01.09.png

円を選択した状態で__Tabキー__で編集モードにします。
顔の白い部分に合わせて移動します。
スクリーンショット 2021-11-14 10.03.26.png

一度__Tabキー__でオブジェクトモードに戻り、
__UV球__と__円__の両方を選択した状態で__Tabキー__で編集モードに変更します。
また、その両方を選択した状態で__メッシュ__から__ナイフ投影__を選択。
スクリーンショット 2021-11-14 10.03.52.png

すると円の形にUV球が切り抜けます。
この要領で目やひげも切り抜いていきます。
スクリーンショット 2021-11-14 10.07.03.png

目やひげ、口、耳を追加し、ナイフ投影します。
スクリーンショット 2021-11-14 10.53.10.png

ナイフ投影が完了し、各パーツができてきました。
次にマテリアルをつけていきます。
スクリーンショット 2021-11-14 11.08.22.png

マテリアルから__新規__を選択
まずは体全体の緑(#5CC500)を入力
スクリーンショット 2021-11-14 11.08.35.png

UV球を__Aキー__で全選択
__割り当て__を選択
スクリーンショット 2021-11-14 11.08.54.png

右上のシェーディングから、__マテリアルプレビュー__を選択(右から2番目)
緑色を確認できます。
同じ要領で目や耳も色をつけます。
スクリーンショット 2021-11-14 11.09.08.png

白(#FFFFFF)、黒(#000000)、黄色(#E6DB2C)でこのようになります。
スクリーンショット 2021-11-14 11.24.48.png

表面を滑らかにします。
__Tabキー__でオブジェクトモードに変更
UV球を__Aキー__で全選択し、右クリックで__スムースシェード__を追加します。
スクリーンショット 2021-11-14 11.36.49.png

これで完成です。
スクリーンショット 2021-11-14 11.38.48.png

Three.jsで読み込むため、glTF形式でエクスポートします。
ファイル__から__エクスポート
__glTF2.0(.glb/gltf)__を選択。
スクリーンショット 2021-11-14 11.39.16.png

右側の__ジオメトリ__から、__モディファイアを適用__にチェックを入れます。
(他はデフォルトでOK)
ファイル名を入力し、エクスポートします。
スクリーンショット 2021-11-14 11.39.53.png

ここからwebpackとThree.jsで読み込んでいきます。

##5. ファイル構成
ファイル構成は下記の通りです。

.
├── src
│   └── img
│   └── obj
│   │   └── qiitan.glb
│   │
│   └── scripts
│   │   └── components
│   │   │    └── webgl.ts
│   │   └── app.ts
│   │
│   └── static
│   │   └── favicon.ico
│   │
│   └── styles
│   │   └── base
│   │   │    └── base.scss
│   │   │    └── reset.scss
│   │   └── global
│   │   │    └── functions
│   │   │    │    └── functions.scss
│   │   │    │    └── mixins.scss
│   │   │    │    └── mq.scss
│   │   │    └── setting
│   │   │         └── color.scss
│   │   │         └── font.scss
│   │   │         └── size.scss
│   │   └── project
│   │   └── style.scss
│   │
│   └── index.html
│
├── .eslintrc.js
├── .prettierrc.js
├── package-lock.json
├── package.json
├── tsconfig.json
└── webpack.config.js

three.jsは忘れずにインストールしておきます。

npm install three @types/three

##6. Three.jsでglbファイルを読み込む

Three.jsで3Dを表示するために必要なものは下記の通りです。
① 型の定義と設定
② htmlの設定
③ Sceneの設定
④ Cameraの設定
⑤ Rendererの設定
⑥ Lightの設定
⑦ Renderingの設定
⑧ Loaderの設定

まずはthree.jsを使用できるようにします。

webgl.ts
// three.js を使用する
import * as THREE from 'three';

次にthree.jsから、glbファイルを読み込むためのGLTFLoaderをインポートします。

webgl.ts
// GLTFLoader を使用する
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

###① 型の定義と設定

webgl.ts
export default class WebGL {
    winSize: {
        [s: string]: number;
    };
    elms: {
        [s: string]: HTMLElement;
    };
    dpr: number;
    three: {
        scene: THREE.Scene;
        renderer: THREE.WebGLRenderer | null;
        clock: THREE.Clock;
        redraw: Group | null;
        camera: THREE.PerspectiveCamera | null;
        cameraFov: number;
        cameraAspect: number;
    };
    srcObj: string;
    constructor() {
        // ウィンドウサイズを取得
        this.winSize = {
            wd: window.innerWidth,
            wh: window.innerHeight,
        };
        // canvas要素を取得
        this.elms = {
            canvas: document.querySelector('[data-canvas]'),
        };
        // デバイスピクセル比(最大値=2)
        this.dpr = Math.min(window.devicePixelRatio, 2);
        // Three.jsに必要な要素
        this.three = {
            scene: null,
            renderer: null,
            clock: null,
            redraw: null,
            camera: null,
            cameraFov: 50,
            cameraAspect: window.innerWidth / window.innerHeight,
        };
        // 作成したqiitanの3Dモデルを読み込む
        this.srcObj = './obj/qiitan.glb';
        this.init();
    }

###② htmlの設定

canvasを設置する箇所を指定します。

index.html
<body>
    <main>
        <section>
            <div data-canvas></div>
        </section>
    </main>
</body>

###③ Sceneの設定
3D空間の生成を行う設定です。

webgl.ts
initScene(): void {
    // シーンを作成
    this.three.scene = new THREE.Scene();
}

###④ Cameraの設定
3Dを撮影するためのカメラ設定です。

webgl.ts
initCamera(): void {
    // カメラを作成(視野角, スペクト比, near, far)
    this.three.camera = new THREE.PerspectiveCamera(this.three.cameraFov, this.winSize.wd / this.winSize.wh, this.three.cameraAspect, 1000);
    this.three.camera.position.set(0, 0, 9);
}

###⑤ Rendererの設定
レンダリングを行うための設定です。

webgl.ts
initRenderer(): void {
    // レンダラーを作成
    this.three.renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true, // 背景を透明にする
    });
    this.three.renderer.setPixelRatio(this.dpr); // retina対応
    this.three.renderer.setSize(this.winSize.wd, this.winSize.wh); // 画面サイズをセット
    this.three.renderer.physicallyCorrectLights = true;
    this.three.renderer.shadowMap.enabled = true; // シャドウを有効にする
    this.three.renderer.shadowMap.type = THREE.PCFSoftShadowMap; // PCFShadowMapの結果から更に隣り合う影との間を線形補間して描画する
    this.elms.canvas.appendChild(this.three.renderer.domElement); // HTMLにcanvasを追加
    this.three.renderer.outputEncoding = THREE.GammaEncoding; // 出力エンコーディングを定義
}

###⑥ Lightの設定
Lightにはたくさん種類があります。
その時に合ったライトを使用するとより良いサイトができます。

webgl.ts
setLight() {
    // 環境光源(色, 光の強さ)
    const ambientLight = new THREE.AmbientLight(0x666666);
    this.three.scene.add(ambientLight);
}

###⑦ Renderingの設定
3Dを画面に繰り返し描写するための設定です。

webgl.ts
rendering(): void {
    // レンダリングを実行
    requestAnimationFrame(this.rendering.bind(this));
    this.three.renderer.render(this.three.scene, this.three.camera);
}

###⑧ Loaderの設定
作成した3Dモデルの読み込みを設定します。
読み込み完了後にrenderingを実行しています。

webgl.ts
setLoading() {
    // glTF形式の3Dモデルを読み込む
    const loader = new GLTFLoader();
    loader.load(this.srcObj, (obj) => {
        const data = obj.scene;
         // 3Dモデルをredrawに入れる
        this.three.redraw = data;
        // 3Dモデルの初期サイズ設定
        data.scale.set(0.8, 0.8, 0.8);
        // シーンに3Dモデルを追加
        this.three.scene.add(data);
        // レンダリングを開始する
        this.rendering();
    });
}

ここまで設定できたら実行します。

webgl.ts
init(): void {
    this.initScene();
    this.initCamera();
    this.initRenderer();
    this.setLight();
    this.setLoading();
}

ブラウザで確認します。
ばっちり表示できました。
スクリーンショット 2021-11-14 13.46.25.png

7. GSAPでアニメーションをつける

gsapのインストール

npm install gsap

gsapのインポート

webgl.ts
import { gsap } from 'gsap';

最後にGSAPでアニメーションをつけていきます。

Renderingの設定に追加

webgl.ts
rendering(): void {
    // レンダリングを実行
    requestAnimationFrame(this.rendering.bind(this));
    this.three.renderer.render(this.three.scene, this.three.camera);
    // アニメーション開始
    this.animate();// 追加
}

アニメーションの設定

例えばY軸に回転させてみます。

webgl.ts
animate() {
    gsap.config({
        force3D: true,
    });
    const tl = gsap.timeline({
        paused: true,
        defaults: {
            duration: 0.6,
            ease: 'power2.easeOut',
        },
    });
    // 回転させる
    tl.to(this.three.redraw.rotation, {
        duration: 1.6,
        y: 6,
    });
    tl.play();
}

ブラウザで確認してみると、回転していることがわかります。
a.gif

位置やサイズは下記のようにすると設定できます。
チェックしながら好きなアニメーションを設定していきます。

webgl.ts
animate() {
    gsap.config({
        force3D: true,
    });
    const tl = gsap.timeline({
        paused: true,
        defaults: {
            duration: 0.6,
            ease: 'power2.easeOut',
        },
    });
    // 回転させる
    tl.to(this.three.redraw.rotation, {
        duration: 1.6,
        y: 6,
    });
    // サイズを変更する
    tl.to(this.three.redraw.scale, {
        duration: 1.6,
        x: 3,
        y: 3,
        z: 3,
    });
    // 位置を変更する
    tl.to(this.three.redraw.position, {
        duration: 1.6,
        x: 3,
        y: 3,
        z: 3,
    });
    tl.play();
}

##8. 完成
好きなアニメーションやテキストをつけて完成です。
ogp.png

今回作成したサイトが下記になります。
https://kaito-takase.dev/3d-qiita/

Gitにソースコードを置いているので、参考になるところがあればお願いします。
https://github.com/kaitoooo/3d-qiita

予想通り長くなってしまいましたが、ここまで読んでいただきありがとうございました。

##9. 参考
https://suzuri.jp/qiita

44
19
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
44
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?