教育機関向け活用例

5. VRMモデルの操作とアニメーション

このセクションでは、VRMモデルの関節を操作してアニメーションを作成する方法を学びます。

VRMモデルのボーン

VRMモデルには、人間の骨格に対応したボーンがあります。
これを利用することで、アバターの動きを制御することができます。

ボーンの一覧は次の通りです。
よく使うものをハイライトしています。

上半身

  • head : 頭
  • rightEye : 右目
  • leftEye : 左目
  • jaw : 顎
  • neck : 首
  • upperChest : 上胸部
  • chest : 胸
  • spine : 腰(背骨)
  • rightShoulder : 右肩
  • leftShoulder : 左肩
  • rightUpperArm : 右上腕
  • leftUpperArm : 左上腕
  • rightLowerArm : 右ひじ
  • leftLowerArm : 左ひじ
  • rightHand : 右手
  • leftHand : 左手

下半身

  • hips : 腰(体全体の中央)
  • rightUpperLeg : 右足の付け根
  • leftUpperLeg : 左足の付け根
  • rightLowerLeg : 右ひざ
  • leftLowerLeg : 左ひざ
  • rightFoot : 右足
  • leftFoot : 左足
  • rightToes : 右つま先
  • leftToes : 左つま先

手の指

  • 親指
    • rightThumbProximal : 右親指基部
    • rightThumbMetacarpal : 右親指中手骨
    • rightThumbDistal : 右親指先端
    • leftThumbProximal : 左親指基部
    • leftThumbMetacarpal : 左親指中手骨
    • leftThumbDistal : 左親指先端
  • 人指し指
    • rightIndexProximal : 右人差し指基部
    • rightIndexIntermediate : 右人差し指中間
    • rightIndexDistal : 右人差し指先端
    • leftIndexProximal : 左人差し指基部
    • leftIndexIntermediate : 左人差し指中間
    • leftIndexDistal : 左人差し指先端
  • 中指
    • rightMiddleProximal : 右中指基部
    • rightMiddleIntermediate : 右中指中間
    • rightMiddleDistal : 右中指先端
    • leftMiddleProximal : 左中指基部
    • leftMiddleIntermediate : 左中指中間
    • leftMiddleDistal : 左中指先端
  • 薬指
    • rightRingProximal : 右薬指基部
    • rightRingIntermediate : 右薬指中間
    • rightRingDistal : 右薬指先端
    • leftRingProximal : 左薬指基部
    • leftRingIntermediate : 左薬指中間
    • leftRingDistal : 左薬指先端
  • 小指
    • rightLittleProximal : 右小指基部
    • rightLittleIntermediate : 右小指中間
    • rightLittleDistal : 右小指先端
    • leftLittleProximal : 左小指基部
    • leftLittleIntermediate : 左小指中間
    • leftLittleDistal : 左小指先端

VRMモデルのボーンを操作する

ここでは、作成したVRMモデルを sample.vrmという名前で保存したとします。
サンプルのモデルファイルをこちらからダウンロードしても構いません。
モデルファイルは、プログラムのファイルと同じ場所に配置してください。

VRMモデルのボーンを取得するには、モデル.bone(ボーン名) を使います。
得られたボーンは、rotation で回転操作を行うことができます。
例えば、右上腕を回転させる場合、次のようにします。

model.bone("rightUpperArm").rotation.z = 回転角

モデルのボーンを操作した場合、最後に model.update(delta) をしないと変更が反映されません。

今の場合、次のようにすると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,
  }
})

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

animate(({ time, delta }) => {
  if (model) {
    model.bone("rightUpperArm").rotation.z = Math.sin(time) * Math.PI * 0.25
    model.update(delta)
  }
})

決まった回転角で固定するなら、読み込み時に指定することもできます。
下の例は、右上腕、右ひじ、首、頭をアニメーションさせつつ、左上腕は固定の角度で固定する例です。

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
  model.bone("leftUpperArm").rotation.z = Math.PI * 0.4
})

animate(({ time, delta }) => {
  if (model) {
    model.bone("rightUpperArm").rotation.z = Math.sin(time) * Math.PI * 0.25
    model.bone("neck").rotation.x = Math.sin(time) * Math.PI * 0.25
    model.bone("head").rotation.y = Math.cos(time * 1.6) * Math.PI * 0.25
    model.bone("rightLowerArm").rotation.y = -Math.sin(time * 1.4) * Math.PI * 0.25 + Math.PI * 0.25
    model.update(delta)
  }
})

VRMモデルのボーンを操作するときに大切なことは、 「自分の体でその動きをするとき、なにを動かしているのか」 を意識することです。
例えば上を向く場合は「頭が回転」します。
一方で、右を向く場合は「首が回転」することで、 結果的に頭も回転しているように見えます(が、実際は首と頭の間の関係は変わっていないので頭は回転していません)。

VRMの表情を変える

モデルの表情を変えるには、

model.expressionManager.setValue("表情名", 強さ)

とします。
強さは0から1の間で指定します。
ボーンと同様に、model.update(delta) をしないと変更が反映されません。
表情名は次のものがあります。

  • aa : 「あ」の口の形
  • ih : 「い」の口の形
  • ou : 「う」の口の形
  • ee : 「え」の口の形
  • oh : 「お」の口の形
  • blink : 両目を閉じる
  • blinkLeft : 左目を閉じる
  • blinkRight : 右目を閉じる
  • lookDown : 下を見る
  • lookLeft : 左を見る
  • lookRight : 右を見る
  • lookUp : 上を見る
  • happy : 嬉しい
  • angry : 怒り
  • sad : 悲しい
  • surprised : 驚き
  • neutral : ニュートラル
  • relaxed : リラックス

モデルによっては、該当する表情がない場合があります。

例えば、次のように記述すると、 嬉しい表情と通常の表情を繰り返します。

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(({ time, delta }) => {
  if (model) {
    model.expressionManager.setValue("happy", Math.sin(time)*0.5 + 0.5)
    model.update(delta)
  }
})