##概要
今回はQiitaのキャラクター(Qiitan)の3Dモデルを作成し、Three.jsで表示するサイト作成まで書いていこうと思います。
長くなってしまいますが、参考になるところがあれば嬉しいです。
##対象
・ Blenderをやってみたい人
・ Three.jsを使って3Dモデルのサイトを作ってみたい人
・ webpackを使った開発環境がある人(※webpackの細かい説明は省略しているため)
##目次
- バージョンなど
- Blenderのダウンロード
- よく使うショートカット
- BlenderでQiitanを作成
- ファイル構成
- Three.jsでglbファイルを読み込む
- GSAPでアニメーションをつける
- 完成
- 参考
##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
デフォルトで設置されているカメラ、メッシュ、ライトを削除します。
__Aキー__で全選択し、__Xキー__で削除を選択。
右上のナビゲートで__-Y(画像赤四角)__をクリックし、作業画面を設定します。
__Shift + Aキー__で__画像__から__背景__を選択。
__Shift + Aキー__で__メッシュ__から__UV球__を選択。
UV球を選択した状態で__Tabキー__で編集モードにします。
右上の__オブジェクトの透明化(画像赤四角)__を有効にして、先程追加した背景画像を見られるようにします。
UV球を選択した状態で、__Sキー__でUV球をQiitanの全体サイズに合わせます。
左側半分を選択し、__Xキー__で__頂点__を削除します。
右側全体を選択し、__モディファイアの追加__から__ミラー__を選択。
__クリッピング__にチェックを入れます。
これで簡単に左右対称のモデルが作成できるようになります。
上部真ん中にある__プロポーショナル編集(画像赤四角)__を有効にして、耳を作成します。
(この時右側だけ動かせば自動的に左側も同じように動きます。)
耳を丸くしたいので、__Ctrl + Bキー__でベベルをします。
幅1m、__セグメントは5__とします。
増やした頂点を背景画像に合わせて__Gキー__で移動します。
ここまでできたらミラーを終了します。
__Tabキー__でオブジェクトモードに変更し、__ミラーの「∨」__から__適用__を選択。
次に尻尾を作っていきます。
__3キー(または左上の赤四角をクリック)__で面選択モードに変更。
右後ろの4面を選択します。
右上のナビゲートで__-Y__をクリックし、作業画面を設定。
尻尾に合わせて__Gキー__で頂点を移動していきます。
(1キー、または赤四角をクリックで頂点選択モードに変更できます。)
頂点が足りないときは__Ctrl + R__(ループカット)で頂点を増やします。
__Tabキー__でオブジェクトモードに変更。
__Shift + A__で__メッシュ__から__円__を追加します。
X軸方向に90度回転するために
Rキー、Xキー、__90__の順で入力します。
円を選択した状態で__Tabキー__で編集モードにします。
顔の白い部分に合わせて移動します。
一度__Tabキー__でオブジェクトモードに戻り、
__UV球__と__円__の両方を選択した状態で__Tabキー__で編集モードに変更します。
また、その両方を選択した状態で__メッシュ__から__ナイフ投影__を選択。
すると円の形にUV球が切り抜けます。
この要領で目やひげも切り抜いていきます。
ナイフ投影が完了し、各パーツができてきました。
次にマテリアルをつけていきます。
マテリアルから__新規__を選択
まずは体全体の緑(#5CC500)を入力
右上のシェーディングから、__マテリアルプレビュー__を選択(右から2番目)
緑色を確認できます。
同じ要領で目や耳も色をつけます。
白(#FFFFFF)、黒(#000000)、黄色(#E6DB2C)でこのようになります。
表面を滑らかにします。
__Tabキー__でオブジェクトモードに変更
UV球を__Aキー__で全選択し、右クリックで__スムースシェード__を追加します。
Three.jsで読み込むため、glTF形式でエクスポートします。
ファイル__から__エクスポート
__glTF2.0(.glb/gltf)__を選択。
右側の__ジオメトリ__から、__モディファイアを適用__にチェックを入れます。
(他はデフォルトでOK)
ファイル名を入力し、エクスポートします。
ここから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を使用できるようにします。
// three.js を使用する
import * as THREE from 'three';
次にthree.jsから、glbファイルを読み込むためのGLTFLoaderをインポートします。
// GLTFLoader を使用する
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
###① 型の定義と設定
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を設置する箇所を指定します。
<body>
<main>
<section>
<div data-canvas></div>
</section>
</main>
</body>
###③ Sceneの設定
3D空間の生成を行う設定です。
initScene(): void {
// シーンを作成
this.three.scene = new THREE.Scene();
}
###④ Cameraの設定
3Dを撮影するためのカメラ設定です。
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の設定
レンダリングを行うための設定です。
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にはたくさん種類があります。
その時に合ったライトを使用するとより良いサイトができます。
setLight() {
// 環境光源(色, 光の強さ)
const ambientLight = new THREE.AmbientLight(0x666666);
this.three.scene.add(ambientLight);
}
###⑦ Renderingの設定
3Dを画面に繰り返し描写するための設定です。
rendering(): void {
// レンダリングを実行
requestAnimationFrame(this.rendering.bind(this));
this.three.renderer.render(this.three.scene, this.three.camera);
}
###⑧ Loaderの設定
作成した3Dモデルの読み込みを設定します。
読み込み完了後にrenderingを実行しています。
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();
});
}
ここまで設定できたら実行します。
init(): void {
this.initScene();
this.initCamera();
this.initRenderer();
this.setLight();
this.setLoading();
}
7. GSAPでアニメーションをつける
gsapのインストール
npm install gsap
gsapのインポート
import { gsap } from 'gsap';
最後にGSAPでアニメーションをつけていきます。
Renderingの設定に追加
rendering(): void {
// レンダリングを実行
requestAnimationFrame(this.rendering.bind(this));
this.three.renderer.render(this.three.scene, this.three.camera);
// アニメーション開始
this.animate();// 追加
}
アニメーションの設定
例えばY軸に回転させてみます。
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();
}
位置やサイズは下記のようにすると設定できます。
チェックしながら好きなアニメーションを設定していきます。
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. 完成
好きなアニメーションやテキストをつけて完成です。
今回作成したサイトが下記になります。
https://kaito-takase.dev/3d-qiita/
Gitにソースコードを置いているので、参考になるところがあればお願いします。
https://github.com/kaitoooo/3d-qiita
予想通り長くなってしまいましたが、ここまで読んでいただきありがとうございました。
##9. 参考
https://suzuri.jp/qiita