Skip to content

Commit 2575c88

Browse files
committed
モデルの読み込みを load → loadAsyncへ変更 / サンプルモデルをCC0 へ変更
1 parent 13cfc65 commit 2575c88

28 files changed

+923
-290
lines changed

docs/model_basic.md

+110-49
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Three.jsでモデルデータを読み込む
33
author: 池田 泰延
44
published_date: 2017-11-03
5-
modified_date: 2023-02-06
5+
modified_date: 2023-03-06
66
---
77

88
**3Dモデリングソフトで制作したモデルデータの読み込み方**を説明します。3Dのモデルデータにはさまざまな形式が存在しますが、Three.jsは対応している形式がです。
@@ -13,7 +13,7 @@ Three.jsでは外部ソフトを利用して作成した3Dモデリングデー
1313

1414
Three.jsでは次の形式の読み込みに対応しています。
1515

16-
* GLTF形式
16+
* GLTF形式(ジーエルティーエフ形式) : インターネット向けの3Dファイル形式。2017年に仕様として定められた新しい形式。
1717
* OBJ形式 : Wavefront社のAdvanced Visualizerというソフト用のファイルフォーマット。テキストデータ。
1818
* Collada(dae)形式 : 汎用的なデータファイル。XMLで構成されている。
1919
* FBX形式(バイナリー)
@@ -26,11 +26,88 @@ Three.jsでは次の形式の読み込みに対応しています。
2626

2727
Three.jsでモデルデータを読み込むには、JavaScriptでThree.jsの初期化を済ませたあとで、ローダーを使ってファイルを読み込み、3D空間に追加するという手順をとります。
2828

29-
データ形式ごとにローダークラスが用意されています。ただ、ローダークラスは、Three.jsライブラリの本体に含まれていないので注意が必要です。公式GitHubの`examples/js/loader`フォルダーにJavaScriptファイルがあるので、これを`script`要素で読み込みます。作業用フォルダーにローダー関連のファイルをコピーしておきましょう
29+
データ形式ごとにローダークラスが用意されています。ただ、ローダークラスは、Three.jsライブラリの本体に含まれていないので注意が必要です。ローダークラスは`script`タグ等で取り込む必要があります
3030

3131

3232

3333

34+
### GLTFファイルの場合
35+
36+
37+
GLTF(ジーエルティーエフ)はインターネット向けの3Dファイル形式です。クロノスグループによって2017年に仕様として定められました。GLTFの中身はJSONファイルを中心として、そこから参照される画像やメッシュデータ等の関連ファイルで構成されています。
38+
39+
40+
GLTFファイルのサンプルは[クロノスグループのGitHub](https://github.com/KhronosGroup/glTF-Sample-Models)から取得できます。
41+
42+
今回は以下のファイルを利用します。ライセンスがPublic domain (CC0) のファイルです。
43+
44+
https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/ToyCar
45+
46+
47+
`gltf`ファイルの場合を読み込むには`GLTFLoader.js`ファイルが必要となります。
48+
49+
```html
50+
<script src="https://unpkg.com/three@0.147.0/examples/js/loaders/GLTFLoader.js"></script>
51+
```
52+
53+
※Three.js r148(2022年12月リリース)より`examples/js`フォルダーでの提供はなくなりました。今後はES Modulesでの利用を推奨されますので、本記事もゆくゆく更新します。
54+
55+
読み込む処理は次のように記載します。`THREE.GLTFLoader`クラスのインスタンスから、`loadAsync()`メソッドを利用します。
56+
引数にはファイルパスを指定します。読み込み完了後に3D空間への追加処理をするのがポイントです。GLTFファイルにはシーンの情報の他に、カメラやライトなどさまざまな情報が含まれます。そのため、シーンの情報だけ抜き出すようにしましょう。
57+
58+
```js
59+
// 非同期処理で待機するのでasync function宣言とする
60+
async function init() {
61+
// ・・・省略
62+
63+
// GLTF形式のモデルデータを読み込む
64+
const loader = new THREE.GLTFLoader();
65+
// GLTFファイルのパスを指定
66+
const gltf = loader.loadAsync('./models/gltf/glTF/ToyCar.gltf');
67+
// 読み込み後に3D空間に追加
68+
const model = gltf.scene;
69+
scene.add(model);
70+
71+
// ・・・省略
72+
}
73+
```
74+
75+
このコードの実行結果は次のとなります。
76+
77+
![](../imgs/loader_glb.png)
78+
79+
- [サンプルを再生する](https://ics-creative.github.io/tutorial-three/samples/loader_gltf.html)
80+
- [サンプルのソースコードを確認する](../samples/loader_gltf.html)
81+
82+
83+
GLTFには、バイナリ形式のGLBがあります。GLTFはテキストデータや関連ファイルがばらけているのに対して、GLBはGLTFを1ファイルにまとめた形式となっています。GLBファイルを読み込む場合も`GLTFLoader`クラスを利用します。コードは先ほど紹介したものとほとんど同じです。
84+
85+
```js
86+
// 非同期処理で待機するのでasync function宣言とする
87+
async function init() {
88+
// ・・・省略
89+
90+
// GLTF形式のモデルデータを読み込む
91+
const loader = new THREE.GLTFLoader();
92+
// GLTFファイルのパスを指定
93+
const objects = loader.loadAsync('./models/gltf/binary/ToyCar.glb');
94+
// 読み込み後に3D空間に追加
95+
const model = objects.scene;
96+
scene.add(model);
97+
98+
// ・・・省略
99+
}
100+
```
101+
102+
103+
- [サンプルを再生する](https://ics-creative.github.io/tutorial-three/samples/loader_glb.html)
104+
- [サンプルのソースコードを確認する](../samples/loader_glb.html)
105+
106+
107+
108+
昔のThree.jsに`loadAsync()`メソッドは存在せず、`load()`メソッドのみ提供されていました。ネット上の記事では、`load()`メソッドで説明されているものが多いですが、`Promise`による非同期処理が苦手でなければ`await``async`を使って制御するといいでしょう。
109+
110+
34111
### 3dsファイルの場合
35112

36113
3dsファイルの場合を読み込むには`TDSLoader.js`ファイルが必要となります。CDNで読み込む場合は以下の`script`タグをHTMLに記述します。
@@ -40,21 +117,27 @@ Three.jsでモデルデータを読み込むには、JavaScriptでThree.jsの初
40117
```
41118
※Three.js r148(2022年12月リリース)より`examples/js`フォルダーでの提供はなくなりました。今後はES Modulesでの利用を推奨されますので、本記事もゆくゆく更新します。
42119

43-
読み込む処理は次のように記載します。`THREE.TDSLoader`クラスのインスタンスから、`load`メソッドを利用します。
44-
第一引数にはファイルパスを指定し、第二引数に読み込み後のコールバック関数を指定します。コールバック関数内で3D空間への追加処理をするのがポイントです
120+
読み込む処理は次のように記載します。`THREE.TDSLoader`クラスのインスタンスから、`loadAsync()`メソッドを利用します。戻り値として`Promise`オブジェクトを返すので`await``async`で待機します
121+
引数にはファイルパスを指定します
45122

46123
なお、3dsファイルのテクスチャーのパスがずれないように、`setResourcePath`メソッドを使って、明示的にテクスチャーが含まれるフォルダーのパスを指定します。
47124

48125
```js
49-
// 3DS形式のモデルデータを読み込む
50-
const loader = new THREE.TDSLoader();
51-
// テクスチャーのパスを指定
52-
loader.setResourcePath('models/3ds/portalgun/textures/');
53-
// 3dsファイルのパスを指定
54-
loader.load('models/3ds/portalgun/portalgun.3ds', (object) => {
126+
// 非同期処理で待機するのでasync function宣言とする
127+
async function init() {
128+
// ・・・省略
129+
130+
// 3DS形式のモデルデータを読み込む
131+
const loader = new THREE.TDSLoader();
132+
// テクスチャーのパスを指定
133+
loader.setResourcePath('models/3ds/portalgun/textures/');
134+
// 3dsファイルのパスを指定
135+
const object = loader.loadAsync('models/3ds/portalgun/portalgun.3ds');
55136
// 読み込み後に3D空間に追加
56137
scene.add(object);
57-
});
138+
139+
// ・・・省略
140+
}
58141
```
59142

60143
このコードの実行結果は次のとなります。
@@ -64,6 +147,9 @@ loader.load('models/3ds/portalgun/portalgun.3ds', (object) => {
64147
- [サンプルを再生する](https://ics-creative.github.io/tutorial-three/samples/loader_3ds.html)
65148
- [サンプルのソースコードを確認する](../samples/loader_3ds.html)
66149

150+
151+
152+
67153
### Colladaファイルの場合
68154

69155
Colladaファイル(拡張子は`.dae`)の場合を読み込むには`ColladaLoader.js`ファイルが必要となります。
@@ -74,18 +160,23 @@ Colladaファイル(拡張子は`.dae`)の場合を読み込むには`Collad
74160

75161
※Three.js r148(2022年12月リリース)より`examples/js`フォルダーでの提供はなくなりました。今後はES Modulesでの利用を推奨されますので、本記事もゆくゆく更新します。
76162

77-
読み込む処理は次のように記載します。`THREE.ColladaLoader`クラスのインスタンスから、`load`メソッドを利用します。
78-
第一引数にはファイルパスを指定し、第二引数に読み込み後のコールバック関数を指定します。コールバック関数内で3D空間への追加処理をするのがポイントです。Colladaファイルにはシーンの情報の他に、カメラやライトなどさまざまな情報が含まれます。そのため、コールバック関数の引数から、シーンの情報だけ抜き出すようにしましょう。
163+
読み込む処理は次のように記載します。`THREE.ColladaLoader`クラスのインスタンスから、`loadAsync()`メソッドを利用します。
164+
引数にはファイルパスを指定します。読み込み完了後に3D空間への配置処理をするのがポイントです。Colladaファイルにはシーンの情報の他に、カメラやライトなどさまざまな情報が含まれます。そのため、シーンの情報だけ抜き出すようにしましょう。
79165

80166
```js
81-
// Collada形式のモデルデータを読み込む
82-
const loader = new THREE.ColladaLoader();
83-
// Colladaファイルのパスを指定
84-
loader.load('./models/collada/elf/elf.dae', (collada) => {
167+
// 非同期処理で待機するのでasync function宣言とする
168+
async function init() {
169+
// ・・・省略
170+
171+
// Collada形式のモデルデータを読み込む
172+
const loader = new THREE.ColladaLoader();
173+
// Colladaファイルのパスを指定
174+
const collada = await loader.loadAsync('./models/collada/elf/elf.dae');
85175
// 読み込み後に3D空間に追加
86176
const model = collada.scene;
87177
scene.add(model);
88-
});
178+
// ・・・省略
179+
}
89180
```
90181

91182
このコードの実行結果は次のとなります。
@@ -95,36 +186,6 @@ loader.load('./models/collada/elf/elf.dae', (collada) => {
95186
- [サンプルを再生する](https://ics-creative.github.io/tutorial-three/samples/loader_dae.html)
96187
- [サンプルのソースコードを確認する](../samples/loader_dae.html)
97188

98-
### GLTFファイルの場合
99-
100-
`gltf`ファイルの場合を読み込むには`GLTFLoader.js`ファイルが必要となります。
101-
102-
```html
103-
<script src="https://unpkg.com/three@0.147.0/examples/js/loaders/GLTFLoader.js"></script>
104-
```
105-
106-
※Three.js r148(2022年12月リリース)より`examples/js`フォルダーでの提供はなくなりました。今後はES Modulesでの利用を推奨されますので、本記事もゆくゆく更新します。
107-
108-
読み込む処理は次のように記載します。`THREE.GLTFLoader`クラスのインスタンスから、`load`メソッドを利用します。
109-
第一引数にはファイルパスを指定し、第二引数に読み込み後のコールバック関数を指定します。コールバック関数内で3D空間への追加処理をするのがポイントです。Colladaファイルにはシーンの情報の他に、カメラやライトなどさまざまな情報が含まれます。そのため、コールバック関数の引数から、シーンの情報だけ抜き出すようにしましょう。
110-
111-
```js
112-
// GLTF形式のモデルデータを読み込む
113-
const loader = new THREE.GLTFLoader();
114-
// GLTFファイルのパスを指定
115-
loader.load('./models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf', (gltf) => {
116-
// 読み込み後に3D空間に追加
117-
const model = gltf.scene;
118-
scene.add(model);
119-
});
120-
```
121-
122-
このコードの実行結果は次のとなります。
123-
124-
![](../imgs/loader_gltf.png)
125-
126-
- [サンプルを再生する](https://ics-creative.github.io/tutorial-three/samples/loader_gltf.html)
127-
- [サンプルのソースコードを確認する](../samples/loader_gltf.html)
128189

129190
### まとめ
130191

imgs/loader_glb.png

1020 KB
Loading

imgs/loader_gltf.png

-787 KB
Binary file not shown.

samples/loader_3ds.html

+8-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
// ページの読み込みを待つ
1010
window.addEventListener('DOMContentLoaded', init);
1111

12-
function init() {
12+
// 非同期処理で待機するのでasync function宣言とする
13+
async function init() {
1314
// サイズを指定
1415
const width = 960;
1516
const height = 540;
@@ -31,7 +32,7 @@
3132
camera.position.set(0, 0, 5);
3233

3334
// カメラコントローラーを作成
34-
const controls = new THREE.OrbitControls(camera, canvasElement);
35+
new THREE.OrbitControls(camera, canvasElement);
3536

3637
// 平行光源を作成
3738
const directionalLight = new THREE.DirectionalLight(0xffffff);
@@ -41,15 +42,15 @@
4142
const ambientLight = new THREE.AmbientLight(0xffffff);
4243
scene.add(ambientLight);
4344

44-
// 3DS形式のモデルデータを読み込む
45+
// 3DS形式(3DS Max) のモデルデータを読み込む
4546
const loader = new THREE.TDSLoader();
4647
// テクスチャーのパスを指定
4748
loader.setResourcePath('models/3ds/portalgun/textures/');
4849
// 3dsファイルのパスを指定
49-
loader.load('models/3ds/portalgun/portalgun.3ds', (object) => {
50-
// 読み込み後に3D空間に追加
51-
scene.add(object);
52-
});
50+
const object = await loader.loadAsync('models/3ds/portalgun/portalgun.3ds');
51+
52+
// 読み込み後に3D空間に追加
53+
scene.add(object);
5354

5455
tick();
5556
// 毎フレーム時に実行されるループイベントです

samples/loader_dae.html

+6-6
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
// ページの読み込みを待つ
1010
window.addEventListener('DOMContentLoaded', init);
1111

12-
function init() {
12+
// 非同期処理で待機するのでasync function宣言とする
13+
async function init() {
1314
// サイズを指定
1415
const width = 960;
1516
const height = 540;
@@ -46,11 +47,10 @@
4647
// Collada形式のモデルデータを読み込む
4748
const loader = new THREE.ColladaLoader();
4849
// Colladaファイルのパスを指定
49-
loader.load('./models/collada/elf/elf.dae', (collada) => {
50-
// 読み込み後に3D空間に追加
51-
const model = collada.scene;
52-
scene.add(model);
53-
});
50+
const collada = await loader.loadAsync('./models/collada/elf/elf.dae');
51+
// 読み込み後に3D空間に追加
52+
const model = collada.scene;
53+
scene.add(model);
5454

5555
tick();
5656

samples/loader_glb.html

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<html>
2+
<head>
3+
<meta charset="utf-8" />
4+
<script src="https://unpkg.com/three@0.147.0/build/three.min.js"></script>
5+
<script src="https://unpkg.com/three@0.147.0/examples/js/controls/OrbitControls.js"></script>
6+
<script src="https://unpkg.com/three@0.147.0/examples/js/loaders/GLTFLoader.js"></script>
7+
8+
<script>
9+
// ページの読み込みを待つ
10+
window.addEventListener('DOMContentLoaded', init);
11+
12+
// 非同期処理で待機するのでasync function宣言とする
13+
async function init() {
14+
// サイズを指定
15+
const width = 960;
16+
const height = 540;
17+
18+
// レンダラーを作成
19+
const canvasElement = document.querySelector('#myCanvas');
20+
const renderer = new THREE.WebGLRenderer({
21+
canvas: canvasElement,
22+
});
23+
renderer.setPixelRatio(window.devicePixelRatio);
24+
renderer.setSize(width, height);
25+
26+
// シーンを作成
27+
const scene = new THREE.Scene();
28+
29+
// カメラを作成
30+
const camera = new THREE.PerspectiveCamera(45, width / height, 0.001, 10000);
31+
// カメラの初期座標を設定
32+
camera.position.set(1, 1, 1);
33+
34+
// カメラコントローラーを作成
35+
const controls = new THREE.OrbitControls(camera, canvasElement);
36+
controls.target.set(0, 0, 0);
37+
controls.update();
38+
39+
// 平行光源を作成
40+
// 上から照らす
41+
const directionalLight = new THREE.DirectionalLight(0xffffff);
42+
directionalLight.position.set(1, 1, 1);
43+
scene.add(directionalLight);
44+
45+
// 横からテラス
46+
const directionalLight2 = new THREE.DirectionalLight(0xffffff);
47+
directionalLight2.position.set(1, 0, 1);
48+
scene.add(directionalLight2);
49+
50+
// GLTF形式のモデルデータを読み込む
51+
const loader = new THREE.GLTFLoader();
52+
// GLTFファイルのパスを指定
53+
const objects = await loader.loadAsync('./models/gltf/binary/ToyCar.glb');
54+
// 読み込み後に3D空間に追加
55+
const model = objects.scene;
56+
scene.add(model);
57+
58+
model.scale.set(30, 30, 30); // 大きさ30倍に拡大
59+
60+
tick();
61+
62+
// 毎フレーム時に実行されるループイベントです
63+
function tick() {
64+
// レンダリング
65+
renderer.render(scene, camera);
66+
requestAnimationFrame(tick);
67+
}
68+
}
69+
</script>
70+
</head>
71+
<body>
72+
<canvas id="myCanvas"></canvas>
73+
</body>
74+
</html>

0 commit comments

Comments
 (0)