教育機関向け活用例

4. VRMモデルを用いたアバターの表示

このセクションでは、VRMモデルを用いてアバターを表示する方法を学びます。

VRMモデルの作成

VRMモデルは、3Dモデルの一種で、人間の形をしたアバターです。
VRMモデルは、表情やポーズなどの情報を持っているため、リアルな人間の動きを再現することができます。

VRMモデルは無料で作成することができます。
例えば、VRoid Studioというソフトウェアを使うと、簡単にVRMモデルを作成することができます
VRoid Studio は、PC(Window, Mac)はもちろん、 iPadでも利用することができます。

ここでは、作成したVRMモデルを sample.vrmという名前で保存したとします。
サンプルのモデルファイルをこちらからダウンロードしても構いません。

モデルファイルは、プログラムのファイルと同じ場所に配置してください。

VRMモデルの表示

VRMモデルを読み込むには、load.vrm(モデルファイルのパス) を使います。

load.vrm(VRMモデルのパス)

今の場合、次のようにするとVRMモデルが表示されます。

index.html
const { camera, create, animate, controls, load, helper } = init()

controls.connect()
camera.position.set(0, 1.3, -1.5)
controls.target.set(0, 1, 0)

helper.grid({ size: 10 })
helper.axes()

create.ambientLight({ intensity: 0.2 })
create.directionalLight({
  intensity: 2,
  position: [-10, 10, -10]
});

create.plane({
  size: 10,
  rotation: [-Math.PI / 2, 0, 0],
  option: {
    color: 0xaaaaaa,
  }
})

load.vrm("./sample.vrm")

animate()

他のオブジェクトを作るときと同じように、 サイズや位置を調整することができます。

背景画像や環境マップ、テクスチャなどと併用すると、 よりリアルな3Dシーンを作成することができます。

VRMモデルを変数に入れる

読み込んだVRMモデルは、変数に代入して操作することができます。
読み込みは非同期処理なので、変数に入れる場合は 非同期処理の終了時の処理を指定できる then か、 非同期処理の終了を待つ await を利用します。
then を使う場合、後から再代入するためconst ではなく let を使います。

const model = await load.vrm(モデルファイルのパス)
let model
load.vrm(モデルファイルのパス).then(m => model = m)

then を使う場合、model は読み込みが完了するまで undefined です。
つまり、await を使う場合は

const model = load.vrm(モデルファイルのパス)

animate(({ delta }) => {
  // modelの操作
})

と書くことができますが、then を使う場合は

let model
load.vrm(モデルファイルのパス).then(m => model = m)

animate(({ delta }) => {
  if (model) {
    // modelの操作
  }
})

と書く必要があります。

await を利用すると、モデルの読み込みが完了するまで待機します。
通常モデルはそれなりに重いため、読み込みに時間がかかり、 その間なにも表示できないことになります。
また await はトップレベルなどでしか使えないため、 関数内で load.vrm を行う場合には thenを使う必要があります。

これらのことから、VRMモデルを読み込む場合は、 基本的には then を使うことをオススメします。

VRMモデル全体を動かす

VRMモデル全体を動かしたり回転させるには、modelそのものではなく、model.scene を操作します。

index.html
const { camera, create, animate, controls, load, helper } = init()

controls.connect()
camera.position.set(0, 1.3, -1.5)
controls.target.set(0, 1, 0)

helper.grid({ size: 10 })
helper.axes()

create.ambientLight({ intensity: 0.2 })
create.directionalLight({
  intensity: 2,
  position: [-10, 10, -10]
})

create.plane({
  size: 10,
  rotation: [-Math.PI / 2, 0, 0],
  option: {
    color: 0xaaaaaa,
  }
})

let model
load.vrm("./sample.vrm").then(m => model = m)

animate(({ delta }) => {
  if (model) {
    model.scene.rotation.y += delta
  }
})