応用編5: 音声同期とライティングによる仕上げ
本章のゴール
音楽の同期再生と、ライティング設定を習得する。
WebXRでMMDモデルを扱う上で重要な「音」と「光」の扱い方を学びます。
Babylon.jsにおける「音」と「光」の基礎
babylon-mmd特有の機能に触れる前に、ベースとなっているBabylon.jsの標準機能について紹介します。
音の表現に関する機能やクラス
- Sound: 一般的なBGMやSEの再生(自動再生機能やループ制御)をサポートするクラス
- Spatial Audio(空間オーディオ):
Soundクラスなどに備わっている、3D空間での距離や方向による音量減衰をサポートする機能
光の表現に関する機能やクラス
- DirectionalLight: 太陽光のように、空間全体を特定の方向から均一に照らす平行光源のクラス
- PointLight: 電球のように、特定の位置から全方位に光を放つ点光源
- HemisphericLight: 天空光と地面からの照り返しをシミュレートする環境光。シーン全体の基礎的な明るさを確保します。
- Post Processes(ポストプロセス): Bloom(発光)、SSAO(環境遮蔽)、被写界深度(DoF)など、最終描画に対する画面エフェクト。
本章では、これらのBabylon.jsネイティブ機能をbabylon-mmdのキャラクターシステムと連携させる方法を学びます。
1. MMDランタイムによる音楽の同期
babylon-mmdでは、面倒な時間計算を自作する必要はありません。専用のオーディオプレーヤーをアニメーションランタイムにセットするだけで音楽とモーションの同期が保たれます。
import { StreamAudioPlayer } from "babylon-mmd/esm/Runtime/Audio/streamAudioPlayer";
const audioPlayer = new StreamAudioPlayer(scene);
audioPlayer.source = "path/to/your/music.mp3";
audioPlayer.volume = 0.5;
currentMmdRuntime.setAudioPlayer(audioPlayer);
再生や停止の操作は、前章までで紹介した MmdPlayerControl (GUI) を使うか、ランタイムの playAnimation() などを呼び出すだけで、音楽も追従して再生・停止されます。
2. ライティングとMMDのシェーディング
MMDのライティングモデルは「単一のDirectionalLight(平行光源)」のみによって定義されています。
したがって、他のライティング(HemisphericLightなど)を追加すると、元のMMDソフトウェアとは異なるシェーディング(影の出方や色の見え方)になってしまう可能性があります。
WebXR(VRゴーグル)のライティング設定
PCでは余裕で動く設定でも、VRゴーグルでは途端に処理落ちカクつきが発生します。
これを防ぎつつ見栄えを担保するため、軽量かつ効果的な構成が重要です。例えば以下のような組み合わせが考えられます。
1. 光源は DirectionalLight 1灯のみ
PointLightなどを複数配置すると、光と影の計算量が光源の数だけ乗算され、VRでは致命的な重さになります。MMDの本来のシェーディングを正確に保つ意味でも、基本の光源はDirectionalLight1つに留めます。
2. 軽量な Bloom(発光エフェクト)の活用
Babylon.jsには様々な画面エフェクト(ポストプロセス)が用意されています。VR向けには、処理が重い環境遮蔽(SSAO)や被写界深度(DoF)は見送り、比較的計算が軽い Bloom(発光エフェクト)を採用します。
Bloomは、ライブステージの照明や発光するマテリアルといった空間演出に効果を発揮します。
import { DefaultRenderingPipeline } from "@babylonjs/core/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline";
// true を指定してデフォルトカメラにアタッチ
const defaultPipeline = new DefaultRenderingPipeline("default", true, scene);
// アンチエイリアスとBloom(発光エフェクト)のみ有効化
defaultPipeline.fxaaEnabled = true;
defaultPipeline.bloomEnabled = true;
defaultPipeline.bloomWeight = 0.5;
// WebXR起動時に、VR用のカメラにもパイプラインを適用する
const xrHelper = await scene.createDefaultXRExperienceAsync({});
if (xrHelper.baseExperience) {
xrHelper.baseExperience.sessionManager.onXRFrameObservable.addOnce(() => {
defaultPipeline.addCamera(xrHelper.baseExperience.camera);
});
}
VRゴーグルのスペック次第でPCと変わらない体験をすることも可能です。
いろいろ試してみましょう。
お疲れ様でした。光の表現は処理を重くする原因となりますが、非常に重要な要素です。